[
  {
    "path": ".gitignore",
    "content": "\n.DS_Store\n*.iml\n*.xml\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM python:3.6-alpine\n\n\nENV LIBRARY_PATH=/lib:/usr/lib \\\n    USER_NAME='' \\\n    USER_PASSWORD=''\n\nWORKDIR /app\n\nRUN echo https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.8/main > /etc/apk/repositories; \\\n    echo https://mirrors.tuna.tsinghua.edu.cn/alpine/v3.8/community >> /etc/apk/repositories\n\nRUN apk add --no-cache libpng freetype libstdc++ libjpeg-turbo\n\nRUN apk add --no-cache --virtual .build-deps \\\n    python-dev \\\n    py-pip \\\n    jpeg-dev \\ \n    zlib-dev \\\n    \\\n    gcc \\\n    build-base \\\n    libpng-dev \\\n    musl-dev \\\n    freetype-dev\n\nRUN ln -s /usr/include/locale.h /usr/include/xlocale.h\n\nRUN apk add --no-cache git && \\\n    git clone https://github.com/yjqiang/bilibili-live-tools /app && \\\n    pip install --no-cache-dir -r requirements.txt && \\\n    rm -r /var/cache/apk && \\\n    rm -r /usr/share/man && \\\n    apk del .build-deps\n\nENTRYPOINT git pull && \\\n    pip install --no-cache-dir -r requirements.txt && \\\n    sed -i ''\"$(cat conf/bilibili.toml -n | grep \"username = \\\"\\\"\" | awk '{print $1}')\"'c '\"$(echo \"username = \\\"${USER_NAME}\\\"\")\"'' conf/bilibili.toml && \\\n    sed -i ''\"$(cat conf/bilibili.toml -n | grep \"password = \\\"\\\"\" | awk '{print $1}')\"'c '\"$(echo \"password = \\\"${USER_PASSWORD}\\\"\")\"'' conf/bilibili.toml && \\\n    python ./run.py\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Dawnspace\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "OnlineHeart.py",
    "content": "from online_net import OnlineNet\nimport time\nimport asyncio\nimport printer\n\n\ndef CurrentTime():\n    currenttime = int(time.time())\n    return currenttime\n\n\nasync def heartbeat():\n    printer.info([\"心跳\"], True)\n    json_response = await OnlineNet().req('apppost_heartbeat')\n    json_response = await OnlineNet().req('pcpost_heartbeat')\n    json_response = await OnlineNet().req('heart_gift')\n    # print('pcpost_heartbeat', json_response)\n\n\n# 因为休眠时间差不多,所以放到这里,此为实验性功能\nasync def draw_lottery():\n    blacklist = ['test', 'TEST', '测试', '加密']\n    max = 10000\n    min = 50\n    while max > min:\n        # print(min, max)\n        middle = int((min + max + 1) / 2)\n        code_middle = (await OnlineNet().req('get_lotterylist', middle))[\"code\"]\n        if code_middle:\n            code_middle1 = (await OnlineNet().req('get_lotterylist', middle + 1))['code']\n            code_middle2 = (await OnlineNet().req('get_lotterylist', middle + 2))['code']\n            if code_middle1 and code_middle2:\n                max = middle - 1\n            else:\n                min = middle + 1\n        else:\n            min = middle\n    print('最新实物抽奖id为', min, max)\n    for i in range(max - 30, max + 1):\n        json_response = await OnlineNet().req('get_lotterylist', i)\n        print('id对应code数值为', json_response['code'], i)\n        # -400 不存在\n        if not json_response['code']:\n            temp = json_response['data']['title']\n            if any(word in temp for word in blacklist):\n                print(\"检测到疑似钓鱼类测试抽奖，默认不参与，请自行判断抽奖可参与性\")\n                # print(temp)\n            else:\n                check = json_response['data']['typeB']\n                for g, value in enumerate(check):\n                    join_end_time = value['join_end_time']\n                    join_start_time = value['join_start_time']\n                    ts = CurrentTime()\n                    if int(join_end_time) > int(ts) > int(join_start_time):\n                        json_response1 = await OnlineNet().req('get_gift_of_lottery', i, g)\n                        printer.info([f'参与实物抽奖回显：{json_response1}'], True)\n        \n        \nasync def run():\n    while 1:\n        # login.HandleExpire()\n        await heartbeat()\n        # await draw_lottery()\n        await asyncio.sleep(300)\n\n\n"
  },
  {
    "path": "README.md",
    "content": "# bilibili-live-tools\n:no_entry: [DEPRECATED]  \n~~单用户比利脚本~~  \n***1.本项目作为老项目已经被新项目取代 https://github.com/yjqiang/bili2.0***    \n2.新项目初期只是想作为多用户分支，结果做完后发现，比老项目做了很多。比如结构优化、很多函数调整、web_session 独立以及一些新的功能等，而且对单用户也很友好  \n3.旧项目不再提供任何代码上的修改等，***完全废除***。但是这里面的已存在的 issue 仍然继续追踪  \n\n\nyjqiang分支是一个次分支，再次感谢主分支所有参与者的基础奠定\n\n## Docker使用介绍\n- 直接拉取构建好的Docker镜像\n\n```\ndocker run -d -e USER_NAME=B站登陆账户 -e USER_PASSWORD=登陆密码 --name 容器名字(随意) zuosc/bilibili-live-tools-python\n```\neg: docker run -d -e USER_NAME=xxxxxxxxxxx -e USER_PASSWORD=pwd --name bilibili zuosc/bilibili-live-tools-python\n\n\n- 本地构建Docker镜像\n\n1、构建镜像\n\n```\ndocker build -t image名称 .\n```\neg:\ndocker build -t bilibili_img .\n\n\n2、运行镜像\n\n```\ndocker run -d -e USER_NAME=B站登陆账户 -e USER_PASSWORD=登陆密码 --name 容器名字(随意) image名称\n```\neg: docker run -d -e USER_NAME=xxxxxxxxxxx -e USER_PASSWORD=pwd --name bilibili bilibili_img\n\n\n## 其他版本Docker使用介绍\ndocker使用 https://github.com/Muromi-Rikka/bilibili-live-tools-docker  \ndocker使用  https://github.com/zsnmwy/bilibili-live-tools-docker\n\npythonista3(ios) https://www.jianshu.com/p/669e63b5ec2b\n\n依赖包 https://github.com/yjqiang/bilibili-live-tools/blob/master/requirements.txt  \n运行方法  run.py\n\n多用户版本 https://github.com/yjqiang/bili2.0  \n二次开发 https://github.com/Hsury/Bilibili-Toolkit  \n\n目前已完成：\n------\n\n        每日签到\n        双端心跳领取经验\n        领取银瓜子宝箱\n        提交每日任务\n        漫天花雨双端抽奖\n        小电视PC端抽奖\n        领取每日包裹奖励\n        应援团签到\n        获取心跳礼物\n        20倍节奏风暴领取\n        获取总督开通奖励\n        实物抽奖\n        清空当日到期礼物\n        根据亲密度赠送礼物\n        银瓜子硬币双向兑换\n        云端验证码识别\n        主站每日任务（4个）\n\nversion 1.0.0\n------\n      基本稳定\n\nversion 1.1.0\n------\n      抽奖繁忙重试机制建立（目前只支持了tv，因为只有这一个code）\n      开始使用f string代替字符串加法或者format，f string大法好\n      修复b站sb的屏蔽”御姐”用户名关键词这种（倒着切查，其实应该分词查看）\n      结构方面的调整，一些不必要的对象创建被删除\n      简单调整代码style\n      其他细节的改变\n\nversion 2.0\n------\n      摩天大楼多房间\n      主站功能（投币分享等）支持\n      websocket弹幕\n      总督领取\n      token refresh and save cookie \n      Queue队列\n      其他细节的改变   \n\nversion 2.1\n------\n      更新api\n      v4小电视更新\n      支持风纪委员会\n      其他修改  \n\nversion 2.2\n------\n      更新wiki  \n      调整bilitimer,改善漏抽问题  \n      弹幕重连机制修复  \n      实物抽奖机制优化  \n\nversion 3.0  \n------\n      庆祝多用户发布  \n      风纪委基本100%成功率\n    \n      \n\n        \n\n\n环境:\n------  \n        python3.6+\n  \n    \n\n\n感谢:https://github.com/lyyyuna\n\n感谢:https://github.com/lkeme/BiliHelper\n\n感谢:https://github.com/czp3009/bilibili-api  \n\n感谢:https://github.com/lzghzr/bilive_client\n\n\n本项目采用MIT开源协议\n"
  },
  {
    "path": "Silver.py",
    "content": "from online_net import OnlineNet\nimport utils\nimport printer\nimport asyncio\n\n\n# 领取银瓜子\nasync def GetAward():\n    temp = await OnlineNet().req('get_time_about_silver')\n    # print (temp['code'])    #宝箱领完返回的code为-10017\n    if temp['code'] == -10017:\n        printer.info([\"# 今日宝箱领取完毕\"])\n    else:\n        time_start = temp['data']['time_start']\n        time_end = temp['data']['time_end']\n        json_response = await OnlineNet().req('get_silver', time_start, time_end)\n        return json_response\n        \nasync def GetAward_black():\n    temp = await OnlineNet().req('get_time_about_silver')\n    # print (temp['code'])    #宝箱领完返回的code为-10017\n    if temp['code'] == -10017:\n        printer.info([\"# 今日宝箱领取完毕\"])\n    else:\n        time_start = temp['data']['time_start']\n        time_end = temp['data']['time_end']\n        for i in range(50):\n            json_response = await OnlineNet().req('get_silver', time_start, time_end)\n            \n            if json_response['code'] != 400:\n                print('宝箱小黑屋的结果返回', json_response)\n                return json_response\n    \n\nasync def run():\n    while True:\n        printer.info([\"检查宝箱状态\"], True)\n        json_rsp = await GetAward()\n        if json_rsp is None or json_rsp['code'] == -10017:\n            sleeptime = (utils.seconds_until_tomorrow() + 300)\n            await asyncio.sleep(sleeptime)\n        elif not json_rsp['code']:\n            printer.info([\"# 打开了宝箱\"])\n        elif json_rsp['code'] == 400:\n            print('小黑屋')\n            await asyncio.sleep(3600)\n            continue\n            print('小黑屋, 暴力测试中')\n            tasklist = []\n            for i in range(60):\n                task = asyncio.ensure_future(GetAward_black())\n                tasklist.append(task)\n            await asyncio.wait(tasklist, return_when=asyncio.FIRST_COMPLETED)\n            json_rsp = await GetAward()\n            sleeptime = 3 * 60 + 5\n            await asyncio.sleep(sleeptime)\n        else:\n            printer.info([\"# 继续等待宝箱冷却...\"])\n            # 未来如果取消了这个东西就睡眠185s，否则精确睡眠\n            # surplus里面是min，float格式\n            sleeptime = (json_rsp['data'].get('surplus', 3)) * 60 + 5\n            await asyncio.sleep(sleeptime)\n            \n"
  },
  {
    "path": "Tasks.py",
    "content": "from online_net import OnlineNet\nimport asyncio\nfrom configloader import ConfigLoader\nimport utils\nimport printer\nfrom bilitimer import BiliTimer\nimport random\nimport re\nimport json\n\n# 获取每日包裹奖励\nasync def Daily_bag():\n    json_response = await OnlineNet().req('get_dailybag')\n    # no done code\n    for i in json_response['data']['bag_list']:\n        printer.info([f'# 获得包裹 {i[\"bag_name\"]}'])\n    BiliTimer.call_after(Daily_bag, 21600)\n\n\n# 签到功能\nasync def DoSign():\n    # -500 done\n    temp = await OnlineNet().req('get_dosign')\n    printer.info([f'# 签到状态: {temp[\"msg\"]}'])\n    if temp['code'] == -500 and '已' in temp['msg']:\n        sleeptime = (utils.seconds_until_tomorrow() + 300)\n    else:\n        sleeptime = 350\n    BiliTimer.call_after(DoSign, sleeptime)\n\n# 领取每日任务奖励\nasync def Daily_Task():\n    # -400 done/not yet\n    json_response2 = await OnlineNet().req('get_dailytask')\n    printer.info([f'# 双端观看直播:  {json_response2[\"msg\"]}'])\n    if json_response2['code'] == -400 and '已' in json_response2['msg']:\n        sleeptime = (utils.seconds_until_tomorrow() + 300)\n    else:\n        sleeptime = 350\n    BiliTimer.call_after(Daily_Task, sleeptime)\n\nasync def Sign1Group(i1, i2):\n    json_response = await OnlineNet().req('assign_group', i1, i2)\n    if not json_response['code']:\n        data = json_response['data']\n        if data['status']:\n            printer.info([f'# 应援团 {i1} 已应援过'])\n        else:\n            printer.info([f'# 应援团 {i1} 应援成功,获得{data[\"add_num\"]}点亲密度'])\n\n# 应援团签到\nasync def link_sign():\n    json_rsp = await OnlineNet().req('get_grouplist')\n    list_check = json_rsp['data']['list']\n    for i in list_check:\n        asyncio.ensure_future(Sign1Group(i['group_id'], i['owner_uid']))\n    BiliTimer.call_after(link_sign, 21600)\n\nasync def send_expiring_gift():\n    task_control = ConfigLoader().dic_user['task_control']\n    if task_control['clean-expiring-gift']:\n        argvs = await utils.fetch_bag_list(show=False)\n        roomID = task_control['clean-expiring-gift2room']\n        time_set = task_control['set-expiring-time']\n        list_gift = []\n        for i in argvs:\n            left_time = i[3]\n            # 剩余时间少于半天时自动送礼\n            if left_time is not None and 0 < int(left_time) < time_set:\n                list_gift.append(i[:3])\n        if list_gift:\n            print('发现即将过期的礼物', list_gift)\n            if task_control['clean_expiring_gift2all_medal']:\n                print('正在投递其他勋章')\n                list_medal = await utils.fetch_medal(show=False)\n                list_gift = await full_intimate(list_gift, list_medal)\n                \n            print('正在清理过期礼物到指定房间')\n            for i in list_gift:\n                giftID = i[0]\n                giftNum = i[1]\n                bagID = i[2]\n                await utils.send_gift_web(roomID, giftNum, bagID, giftID)\n        else:\n            print('未发现即将过期的礼物')\n\nasync def send_medal_gift():\n    list_medal = []\n    task_control = ConfigLoader().dic_user['task_control']\n    if task_control['send2wearing-medal']:\n        list_medal = await utils.WearingMedalInfo()\n        if not list_medal:\n            print('暂未佩戴任何勋章')\n    if task_control['send2medal']:\n        list_medal += await utils.fetch_medal(False, task_control['send2medal'])\n    # print(list_medal)\n    print('正在投递勋章')\n    temp = await utils.fetch_bag_list(show=False)\n    # print(temp)\n    list_gift = []\n    for i in temp:\n        gift_id = int(i[0])\n        left_time = i[3]\n        if (gift_id not in [4, 3, 9, 10]) and left_time is not None:\n            list_gift.append(i[:3])\n    await full_intimate(list_gift, list_medal)\n\nasync def send_gift():\n    await send_medal_gift()\n    await send_expiring_gift()\n    BiliTimer.call_after(send_gift, 21600)\n\nasync def full_intimate(list_gift, list_medal):\n    json_res = await OnlineNet().req('gift_list')\n    dic_gift = {j['id']: int(j['price'] / 100) for j in json_res['data']}\n    for roomid, score_wanted, medal_name in list_medal:\n        sum_score = 0\n        for i in list_gift:\n            gift_id, gift_num, bag_id = i\n            price = dic_gift[gift_id]\n            left_score = score_wanted - sum_score\n            if price * gift_num <= left_score:\n                num_wanted = gift_num\n            elif left_score >= price:\n                num_wanted = int(left_score / price)\n            else:\n                num_wanted = 0\n            await utils.send_gift_web(roomid, num_wanted, bag_id, gift_id)\n            i[1] -= num_wanted\n            score = price * num_wanted\n            sum_score += score\n        printer.info([f'# 对{medal_name}共送出亲密度为{sum_score}的礼物'])\n    return [i for i in list_gift if i[1]]\n\n\nasync def doublegain_coin2silver():\n    if ConfigLoader().dic_user['task_control']['doublegain_coin2silver']:\n        json_response0 = await OnlineNet().req('request_doublegain_coin2silver')\n        json_response1 = await OnlineNet().req('request_doublegain_coin2silver')\n        print(json_response0['msg'], json_response1['msg'])\n    BiliTimer.call_after(doublegain_coin2silver, 21600)\n\nasync def sliver2coin():\n    if ConfigLoader().dic_user['task_control']['silver2coin']:\n        # 403 done\n        # json_response1 = await OnlineNet().req('silver2coin_app')\n        \n        json_response = await OnlineNet().req('silver2coin_web')\n        printer.info([f'#  {json_response[\"msg\"]}'])\n        \n        if json_response['code'] == 403 and '最多' in json_response['msg']:\n            finish_web = True\n        else:\n            finish_web = False\n\n        if finish_web:\n            sleeptime = (utils.seconds_until_tomorrow() + 300)\n            BiliTimer.call_after(sliver2coin, sleeptime)\n            return\n        else:\n            BiliTimer.call_after(sliver2coin, 350)\n            return\n\n    BiliTimer.call_after(sliver2coin, 21600)\n\nasync def GetVideoExp(list_topvideo):\n    print('开始获取视频观看经验')\n    aid = random.choice(list_topvideo)\n    cid = await utils.GetVideoCid(aid)\n    await OnlineNet().req('Heartbeat', aid, cid)\n\nasync def GiveCoinTask(coin_remain, list_topvideo):\n    i = 0\n    while coin_remain > 0:\n        i += 1\n        if i > 20:\n            print('本次可投票视频获取量不足')\n            return\n        aid = random.choice(list_topvideo)\n        rsp = await utils.GiveCoin2Av(aid, 1)\n        if rsp is None:\n            break\n        elif rsp:\n            coin_remain -= 1\n\nasync def GetVideoShareExp(list_topvideo):\n    print('开始获取视频分享经验')\n    aid = random.choice(list_topvideo)\n    await OnlineNet().req('DailyVideoShare', aid)\n\nasync def BiliMainTask():\n    task_control = ConfigLoader().dic_user['task_control']\n    login, watch_av, num, share_av = await utils.GetRewardInfo()\n    if task_control['fetchrule'] == 'bilitop':\n        list_topvideo = await utils.GetTopVideoList()\n    else:\n        list_topvideo = await utils.fetch_uper_video(task_control['mid'])\n    if (not login) or not watch_av:\n        await GetVideoExp(list_topvideo)\n    coin_sent = num / 10\n    coin_set = min(task_control['givecoin'], 5)\n    coin_remain = coin_set - coin_sent\n    await GiveCoinTask(coin_remain, list_topvideo)\n    if not share_av:\n        await GetVideoShareExp(list_topvideo)\n    # b站傻逼有记录延迟，3点左右成功率高一点\n    BiliTimer.call_after(BiliMainTask, utils.seconds_until_tomorrow() + 10800)\n\n\nasync def check(id):\n    # 3放弃\n    # 2 否 voterule\n    # 4 删除 votedelete\n    # 1 封杀 votebreak\n    text_rsp = await OnlineNet().req('req_check_voted', id)\n    pattern = re.compile(r'\\((.+)\\)')\n    match = pattern.findall(text_rsp)\n    temp = json.loads(match[0])\n    data = temp['data']\n    votebreak = data['voteBreak']\n    voteDelete = data['voteDelete']\n    voteRule = data['voteRule']\n    voted = votebreak+voteDelete+voteRule\n    percent = (voteRule / voted) if voted else 0\n    \n    print(f'\\\"{data[\"originContent\"]}\\\"')\n    print('该案件目前已投票', voted)\n    print('认为言论合理比例', percent)\n    return voted, percent\n    \n    \ndef judge_case(voted, percent):\n    vote = None\n    if voted >= 300:\n        # 认为这里可能出现了较多分歧，抬一手\n        if percent >= 0.4:\n            vote = 2\n        elif percent <= 0.25:\n            vote = 4\n    elif voted >= 150:\n        if percent >= 0.9:\n            vote = 2\n        elif percent <= 0.1:\n            vote = 4\n    elif voted >= 50:\n        if percent >= 0.97:\n            vote = 2\n        elif percent <= 0.03:\n            vote = 4\n    # 抬一手\n    if vote is None and voted >= 400:\n        vote = 2\n        \n    return vote\n               \nasync def judge():\n    num_case = 0\n    num_voted = 0\n    while True:\n        temp = await OnlineNet().req('req_fetch_case')\n        if not temp['code']:\n            id = temp['data']['id']\n            num_case += 1\n        else:\n            print('本次未获取到案件')\n            break\n        \n        wait_time = 0\n        min_percent = 1\n        max_percent = 0\n        while True:\n            voted, percent = await check(id)\n            vote = judge_case(voted, percent)\n            if voted >= 50:\n                min_percent = min(min_percent, percent)\n                max_percent = max(max_percent, percent)\n                print('统计投票波动情况', max_percent, min_percent)\n            \n            if vote is not None:\n                break\n            elif wait_time >= 1200:\n                print('进入二次判定')\n                # 如果case判定中，波动很小，则表示趋势基本一致\n                if 0 <= max_percent - min_percent <= 0.1 and voted > 200:\n                    future_voted = voted + 100\n                    vote0 = judge_case(future_voted, max_percent)\n                    vote1 = judge_case(future_voted, min_percent)\n                    vote = vote0 if vote0 == vote1 else None\n                print('二次判定结果', vote)\n                break\n            else:\n                sleep_time = 180 if voted < 300 else 60\n                printer.info([f'案件{id}暂时无法判定，在{sleep_time}后重新尝试'], True)\n                await asyncio.sleep(sleep_time)\n                wait_time += sleep_time\n        \n        if vote is None:\n            num_voted -= 1\n            vote = 3\n        vote_info = '作废票' if vote == 3 else '有效票'\n        print('该案件的投票决策', id, vote, vote_info)\n        json_rsp = await OnlineNet().req('req_vote_case', id, vote)\n        if not json_rsp['code']:\n            print('该案件的投票结果', id, '投票成功')\n            num_voted += 1\n        else:\n            print('该案件的投票结果', id, '投票失败，请反馈作者')\n        \n        print('______________________________________________')\n    \n    printer.info([f'风纪委员会共获取{num_case}件案例，其中有效投票{num_voted}件'], True)\n    BiliTimer.call_after(judge, 3600)\n        \n\ndef init():\n    BiliTimer.call_after(sliver2coin, 0)\n    BiliTimer.call_after(doublegain_coin2silver, 0)\n    BiliTimer.call_after(DoSign, 0)\n    BiliTimer.call_after(Daily_bag, 0)\n    BiliTimer.call_after(Daily_Task, 0)\n    BiliTimer.call_after(link_sign, 0)\n    BiliTimer.call_after(send_gift, 0)\n    BiliTimer.call_after(BiliMainTask, 0)\n    BiliTimer.call_after(judge, 0)\n    \n"
  },
  {
    "path": "bili_console.py",
    "content": "import sys\nimport utils\nfrom statistics import Statistics\nfrom connect import connect\nimport printer\nfrom configloader import ConfigLoader\nfrom rafflehandler import Rafflehandler\nimport rafflehandler\nimport OnlineHeart\nimport asyncio\nfrom cmd import Cmd\n    \n\ndef fetch_real_roomid(roomid):\n    if roomid:\n        real_roomid = [[roomid], utils.check_room]\n    else:\n        real_roomid = ConfigLoader().dic_user['other_control']['default_monitor_roomid']\n    return real_roomid\n  \n              \nclass Biliconsole(Cmd):\n    prompt = ''\n\n    def __init__(self, loop):\n        self.loop = loop\n        Cmd.__init__(self)\n        \n    def guide_of_console(self):\n        print(' ＿＿＿＿＿＿＿＿＿＿＿＿＿＿＿＿＿＿＿ ')\n        print('|　　　欢迎使用本控制台　　　　　　　　|')\n        print('|　１　输出本次抽奖统计　　　　　　　　|')\n        print('|　２　查看目前拥有礼物的统计　　　　　|')\n        print('|　３　查看持有勋章状态　　　　　　　　|')\n        print('|　４　获取直播个人的基本信息　　　　　|')\n        print('|　５　检查今日任务的完成情况　　　　　|')\n        print('|　６　模拟电脑网页端发送弹幕　　　　　|')\n        print('|　７　直播间的长短号码的转化　　　　　|')\n        print('|　８　手动送礼物到指定直播间　　　　　|')\n        print('|　９　切换监听的直播间　　　　　　　　|')\n        print('|１０　控制弹幕的开关　　　　　　　　　|')\n        print('|１１　房间号码查看主播　　　　　　　　|')\n        print('|１２　当前拥有的扭蛋币　　　　　　　　|')\n        print('|１３　开扭蛋币（一、十、百）　　　　　|')\n        print('|１６　尝试一次实物抽奖　　　　　　　　|')\n        print(' ￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣ ')\n        \n    def default(self, line):\n        self.guide_of_console()\n        \n    def emptyline(self):\n        self.guide_of_console()\n        \n    def do_1(self, line):\n        Statistics.getlist()\n        \n    def do_2(self, line):\n        self.append2list_console(utils.fetch_bag_list)\n        \n    def do_3(self, line):\n        self.append2list_console(utils.fetch_medal)\n        \n    def do_4(self, line):\n        self.append2list_console(utils.fetch_user_info)\n        \n    def do_5(self, line):\n        self.append2list_console(utils.check_taskinfo)\n        \n    def do_6(self, line):\n        msg = input('请输入要发送的信息:')\n        roomid = input('请输入要发送的房间号:')\n        real_roomid = fetch_real_roomid(roomid)\n        self.append2list_console([[msg, real_roomid], utils.send_danmu_msg_web])\n        \n    def do_7(self, line):\n        roomid = input('请输入要转化的房间号:')\n        if not roomid:\n            roomid = ConfigLoader().dic_user['other_control']['default_monitor_roomid']\n        self.append2list_console([[roomid], utils.check_room])\n    \n    def do_8(self, line):\n        self.append2list_console([[True], utils.fetch_bag_list])\n        bagid = input('请输入要发送的礼物编号:')\n        # print('是谁', giftid)\n        giftnum = int(input('请输入要发送的礼物数目:'))\n        roomid = input('请输入要发送的房间号:')\n        real_roomid = fetch_real_roomid(roomid)\n        self.append2list_console([[real_roomid, giftnum, bagid], utils.send_gift_web])\n    \n    def do_9(self, line):\n        roomid = input('请输入roomid')\n        real_roomid = fetch_real_roomid(roomid)\n        self.append2list_console([[real_roomid], connect.reconnect])\n        \n    def do_10(self, line):\n        new_words = input('弹幕控制')\n        if new_words == 'T':\n            printer.control_printer(True, None)\n        else:\n            printer.control_printer(False, None)\n            \n    def do_11(self, line):\n        roomid = input('请输入roomid')\n        real_roomid = fetch_real_roomid(roomid)\n        self.append2list_console([[real_roomid], utils.fetch_liveuser_info])\n    \n    def do_12(self, line):\n        self.append2list_console(utils.fetch_capsule_info)\n        \n    def do_13(self, line):\n        count = input('请输入要开的扭蛋数目(1或10或100)')\n        self.append2list_console([[count], utils.open_capsule])\n        \n    def do_14(self, line):\n        if sys.platform == 'ios':\n            roomid = input('请输入roomid')\n            real_roomid = fetch_real_roomid(roomid)\n            self.append2list_console([[real_roomid], utils.watch_living_video])\n            return\n        print('仅支持ios')\n        \n    def do_15(self, line):\n        self.append2list_console(utils.TitleInfo)\n        \n    def do_16(self, line):\n        self.append2list_console(OnlineHeart.draw_lottery)\n        \n    def do_17(self, line):\n        new_words = input('debug控制')\n        if new_words == 'T':\n            printer.control_printer(None, True)\n        else:\n            printer.control_printer(None, True)\n            \n    def do_18(self, line):\n        video_id = input('请输入av号')\n        num = input('输入数目')\n        self.append2list_console([[int(video_id), int(num)], utils.GiveCoin2Av])\n        \n    def do_19(self, line):\n        try:\n            roomid = int(input('输入roomid'))\n            self.append2list_console([[(roomid,), rafflehandler.handle_1_room_guard], rafflehandler.Rafflehandler.Put2Queue_wait])\n        except:\n            pass\n        \n    def do_check(self, line):\n        Rafflehandler.getlist()\n        Statistics.checklist()\n        \n    def append2list_console(self, request):\n        asyncio.run_coroutine_threadsafe(self.excute_async(request), self.loop)\n        # inst.loop.call_soon_threadsafe(inst.queue_console.put_nowait, request)\n        \n    async def excute_async(self, i):\n        if isinstance(i, list):\n            # 对10号单独简陋处理\n            for j in range(len(i[0])):\n                if isinstance(i[0][j], list):\n                    # print('检测')\n                    i[0][j] = await i[0][j][1](*(i[0][j][0]))\n            if i[1] == 'normal':\n                i[2](*i[0])\n            else:\n                await i[1](*i[0])\n        else:\n            await i()\n    \n    \n    \n"
  },
  {
    "path": "bilibili.py",
    "content": "import sys\nfrom configloader import ConfigLoader\nimport hashlib\nimport time\nimport requests\nimport base64\nimport aiohttp\nimport asyncio\nimport random\nimport json\ntry:\n    from PIL import Image\nexcept ImportError:\n    Image = None\nfrom io import BytesIO\n\n\ndef CurrentTime():\n    currenttime = int(time.time())\n    return str(currenttime)\n\n\ndef randomint():\n    return ''.join(str(random.randint(0, 9)) for _ in range(17))\n\n\ndef cnn_captcha(content):\n    img = base64.b64encode(content)\n    url = \"http://47.95.255.188:5000/code\"\n    data = {\"image\": img}\n    rsp = requests.post(url, data=data)\n    captcha = rsp.text\n    print(f'此次登录出现验证码,识别结果为{captcha}')\n    return captcha\n \n       \ndef input_captcha(content):\n    if Image is not None:\n        img = Image.open(BytesIO(content))\n        # img.thumbnail(size)\n        img.show()\n        captcha = input('手动输入验证码')\n    else:\n        captcha = input('您并没有安装pillow模块，但仍然选择了手动输入，那就输呀:')\n    return captcha\n\n\nbase_url = 'https://api.live.bilibili.com'\n\n\nclass bilibili():\n    __slots__ = ('dic_bilibili', 'var_bili_session', 'app_params', 'var_other_session', 'var_login_session')\n    instance = None\n\n    def __new__(cls, *args, **kw):\n        if not cls.instance:\n            cls.instance = super(bilibili, cls).__new__(cls, *args, **kw)\n            cls.instance.dic_bilibili = ConfigLoader().dic_bilibili\n            dic_bilibili = ConfigLoader().dic_bilibili\n            cls.instance.var_bili_session = None\n            cls.instance.var_other_session = None\n            cls.instance.var_login_session = None\n            cls.instance.app_params = f'actionKey={dic_bilibili[\"actionKey\"]}&appkey={dic_bilibili[\"appkey\"]}&build={dic_bilibili[\"build\"]}&device={dic_bilibili[\"device\"]}&mobi_app={dic_bilibili[\"mobi_app\"]}&platform={dic_bilibili[\"platform\"]}'\n        return cls.instance\n\n    @property\n    def bili_session(self):\n        if self.var_bili_session is None:\n            self.var_bili_session = aiohttp.ClientSession()\n            # print(0)\n        return self.var_bili_session\n        \n    @property\n    def other_session(self):\n        if self.var_other_session is None:\n            self.var_other_session = aiohttp.ClientSession()\n            # print(0)\n        return self.var_other_session\n        \n    @property\n    def login_session(self):\n        if self.var_login_session is None:\n            self.var_login_session = requests.Session()\n            # print(0)\n        return self.var_login_session\n\n    def calc_sign(self, str):\n        str = f'{str}{self.dic_bilibili[\"app_secret\"]}'\n        sign = hashlib.md5(str.encode('utf-8')).hexdigest()\n        return sign\n\n    @staticmethod\n    def load_session(dic):\n        # print(dic)\n        inst = bilibili.instance\n        for i in dic.keys():\n            inst.dic_bilibili[i] = dic[i]\n            if i == 'cookie':\n                inst.dic_bilibili['pcheaders']['cookie'] = dic[i]\n                inst.dic_bilibili['appheaders']['cookie'] = dic[i]\n                \n    def login_session_post(self, url, headers=None, data=None, params=None):\n        while True:\n            try:\n                # print(self.login_session.cookies, url)\n                rsp = self.login_session.post(url, headers=headers, data=data, params=params)\n                if rsp.status_code == requests.codes.ok and rsp.content:\n                    return rsp\n                elif rsp.status_code == 403:\n                    print('403频繁')\n            except:\n                # print('当前网络不好，正在重试，请反馈开发者!!!!')\n                print(sys.exc_info()[0], sys.exc_info()[1], url)\n                continue\n    \n    def login_session_get(self, url, headers=None, data=None, params=None):\n        while True:\n            try:\n                # print(self.login_session.cookies, url)\n                rsp = self.login_session.get(url, headers=headers, data=data, params=params)\n                if rsp.status_code == requests.codes.ok and rsp.content:\n                    return rsp\n                elif rsp.status_code == 403:\n                    print('403频繁')\n            except:\n                # print('当前网络不好，正在重试，请反馈开发者!!!!')\n                print(sys.exc_info()[0], sys.exc_info()[1], url)\n                continue\n                \n    async def get_json_rsp(self, rsp, url):\n        if rsp.status == 200:\n            # json_rsp = await rsp.json(content_type=None)\n            data = await rsp.read()\n            json_rsp = json.loads(data)\n            if isinstance(json_rsp, dict) and 'code' in json_rsp:\n                code = json_rsp['code']\n                if code == 1024:\n                    print('b站炸了，暂停所有请求1.5s后重试，请耐心等待')\n                    await asyncio.sleep(1.5)\n                    return None\n                elif code == 3:\n                    print('api错误，稍后重试，请反馈给作者')\n                    print(json_rsp)\n                    await asyncio.sleep(1)\n                    return 3\n            return json_rsp\n        elif rsp.status == 403:\n            print('403频繁', url)\n        return None\n        \n    async def get_text_rsp(self, rsp, url):\n        if rsp.status == 200:\n            return await rsp.text()\n        elif rsp.status == 403:\n            print('403频繁', url)\n        return None\n\n    async def bili_session_post(self, url, headers=None, data=None, params=None):\n        while True:\n            try:\n                async with self.bili_session.post(url, headers=headers, data=data, params=params) as rsp:\n                    json_rsp = await self.get_json_rsp(rsp, url)\n                    if json_rsp is not None:\n                        return json_rsp\n            except:\n                # print('当前网络不好，正在重试，请反馈开发者!!!!')\n                print(sys.exc_info()[0], sys.exc_info()[1], url)\n                continue\n\n    async def other_session_get(self, url, headers=None, data=None, params=None):\n        while True:\n            try:\n                async with self.other_session.get(url, headers=headers, data=data, params=params) as rsp:\n                    json_rsp = await self.get_json_rsp(rsp, url)\n                    if json_rsp is not None:\n                        return json_rsp\n            except:\n                # print('当前网络不好，正在重试，请反馈开发者!!!!')\n                print(sys.exc_info()[0], sys.exc_info()[1], url)\n                continue\n                \n    async def other_session_post(self, url, headers=None, data=None, params=None):\n        while True:\n            try:\n                async with self.other_session.post(url, headers=headers, data=data, params=params) as rsp:\n                    json_rsp = await self.get_json_rsp(rsp, url)\n                    if json_rsp is not None:\n                        return json_rsp\n            except:\n                # print('当前网络不好，正在重试，请反馈开发者!!!!')\n                print(sys.exc_info()[0], sys.exc_info()[1], url)\n                continue\n\n    async def bili_session_get(self, url, headers=None, data=None, params=None):\n        while True:\n            try:\n                async with self.bili_session.get(url, headers=headers, data=data, params=params) as rsp:\n                    json_rsp = await self.get_json_rsp(rsp, url)\n                    if json_rsp is not None:\n                        return json_rsp\n            except:\n                # print('当前网络不好，正在重试，请反馈开发者!!!!')\n                print(sys.exc_info()[0], sys.exc_info()[1], url)\n                continue\n                \n    async def session_text_get(self, url, headers=None, data=None, params=None):\n        while True:\n            try:\n                async with self.other_session.get(url, headers=headers, data=data, params=params) as rsp:\n                    text_rsp = await self.get_text_rsp(rsp, url)\n                    if text_rsp is not None:\n                        return text_rsp\n            except:\n                # print('当前网络不好，正在重试，请反馈开发者!!!!')\n                print(sys.exc_info()[0], sys.exc_info()[1], url)\n                continue\n\n    @staticmethod\n    async def request_playurl(cid):\n        inst = bilibili.instance\n        # cid real_roomid\n        # url = 'http://api.live.bilibili.com/room/v1/Room/playUrl?'\n        url = f'{base_url}/api/playurl?device=phone&platform=ios&scale=3&build=10000&cid={cid}&otype=json&platform=h5'\n        json_rsp = await inst.bili_session_get(url)\n        return json_rsp\n\n    @staticmethod\n    async def request_search_liveuser(name):\n        inst = bilibili.instance\n        search_url = f'https://search.bilibili.com/api/search?search_type=live_user&keyword={name}&page=1'\n        json_rsp = await inst.other_session_get(search_url)\n        return json_rsp\n\n    @staticmethod\n    async def request_search_biliuser(name):\n        inst = bilibili.instance\n        search_url = f\"https://search.bilibili.com/api/search?search_type=bili_user&keyword={name}\"\n        json_rsp = await inst.other_session_get(search_url)\n        return json_rsp\n\n    @staticmethod\n    async def request_fetch_capsule():\n        inst = bilibili.instance\n        url = f\"{base_url}/api/ajaxCapsule\"\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def request_open_capsule(count):\n        inst = bilibili.instance\n        url = f\"{base_url}/api/ajaxCapsuleOpen\"\n        data = {\n            'type': 'normal',\n            \"count\": count,\n            \"csrf_token\": inst.dic_bilibili['csrf']\n        }\n        json_rsp = await inst.bili_session_post(url, data=data, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    def request_logout():\n        inst = bilibili.instance\n        list_url = f'access_key={inst.dic_bilibili[\"access_key\"]}&access_token={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&ts={CurrentTime()}'\n        list_cookie = inst.dic_bilibili['cookie'].split(';')\n        params = ('&'.join(sorted(list_url.split('&') + list_cookie)))\n        sign = inst.calc_sign(params)\n        true_url = f'https://passport.bilibili.com/api/v2/oauth2/revoke'\n        data = f'{params}&sign={sign}'\n        appheaders = {**(inst.dic_bilibili['appheaders']), 'cookie': ''}\n        rsp = inst.login_session_post(true_url, params=data, headers=appheaders)\n        print(rsp.json())\n        return rsp\n\n    # 1:900兑换\n    @staticmethod\n    async def request_doublegain_coin2silver():\n        inst = bilibili.instance\n        # url: \"/exchange/coin2silver\",\n        data = {'coin': 10}\n        url = f\"{base_url}/exchange/coin2silver\"\n        json_rsp = await inst.bili_session_post(url, data=data, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def post_watching_history(room_id):\n        inst = bilibili.instance\n        data = {\n            \"room_id\": room_id,\n            \"csrf_token\": inst.dic_bilibili['csrf']\n        }\n        url = f\"{base_url}/room/v1/Room/room_entry_action\"\n        json_rsp = await inst.bili_session_post(url, data=data, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def silver2coin_web():\n        inst = bilibili.instance\n        url = f\"{base_url}/pay/v1/Exchange/silver2coin\"\n        data = {\n            \"platform\": 'pc',\n            \"csrf_token\": inst.dic_bilibili['csrf']\n        }\n        json_rsp = await inst.bili_session_post(url, headers=inst.dic_bilibili['pcheaders'], data=data)\n        return json_rsp\n\n    @staticmethod\n    async def silver2coin_app():\n        inst = bilibili.instance\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&ts={CurrentTime()}'\n        sign = inst.calc_sign(temp_params)\n        app_url = f\"{base_url}/AppExchange/silver2coin?{temp_params}&sign={sign}\"\n        json_rsp = await inst.bili_session_post(app_url, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def request_fetch_fan(real_roomid, uid):\n        inst = bilibili.instance\n        url = f'{base_url}/rankdb/v1/RoomRank/webMedalRank?roomid={real_roomid}&ruid={uid}'\n        json_rsp = await inst.bili_session_get(url)\n        return json_rsp\n\n    @staticmethod\n    async def request_check_room(roomid):\n        inst = bilibili.instance\n        url = f\"{base_url}/room/v1/Room/room_init?id={roomid}\"\n        json_rsp = await inst.bili_session_get(url)\n        return json_rsp\n\n    @staticmethod\n    async def request_fetch_bag_list():\n        inst = bilibili.instance\n        url = f\"{base_url}/gift/v2/gift/bag_list\"\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def request_check_taskinfo():\n        inst = bilibili.instance\n        url = f'{base_url}/i/api/taskInfo'\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def request_send_gift_web(giftid, giftnum, bagid, ruid, biz_id):\n        inst = bilibili.instance\n        url = f\"{base_url}/gift/v2/live/bag_send\"\n        data = {\n            'uid': inst.dic_bilibili['uid'],\n            'gift_id': giftid,\n            'ruid': ruid,\n            'gift_num': giftnum,\n            'bag_id': bagid,\n            'platform': 'pc',\n            'biz_code': 'live',\n            'biz_id': biz_id,\n            'rnd': CurrentTime(),\n            'storm_beat_id': '0',\n            'metadata': '',\n            'price': '0',\n            'csrf_token': inst.dic_bilibili['csrf']\n        }\n        json_rsp = await inst.bili_session_post(url, headers=inst.dic_bilibili['pcheaders'], data=data)\n        return json_rsp\n\n    @staticmethod\n    async def request_fetch_user_info():\n        inst = bilibili.instance\n        url = f\"{base_url}/i/api/liveinfo\"\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def request_fetch_user_infor_ios():\n        inst = bilibili.instance\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&platform=ios'\n        url = f'{base_url}/mobile/getUser?{temp_params}'\n        json_rsp = await inst.bili_session_get(url)\n        return json_rsp\n\n    @staticmethod\n    async def request_fetch_liveuser_info(real_roomid):\n        inst = bilibili.instance\n        url = f'{base_url}/live_user/v1/UserInfo/get_anchor_in_room?roomid={real_roomid}'\n        json_rsp = await inst.bili_session_get(url)\n        return json_rsp\n\n    @staticmethod\n    async def request_load_img(url):\n        return await bilibili.instance.other_session.get(url)\n\n    @staticmethod\n    async def request_send_danmu_msg_web(msg, roomId):\n        inst = bilibili.instance\n        url = f'{base_url}/msg/send'\n        data = {\n            'color': '16777215',\n            'fontsize': '25',\n            'mode': '1',\n            'msg': msg,\n            'rnd': '0',\n            'roomid': int(roomId),\n            'csrf_token': inst.dic_bilibili['csrf'],\n            'csrf': inst.dic_bilibili['csrf']\n        }\n\n        json_rsp = await inst.bili_session_post(url, headers=inst.dic_bilibili['pcheaders'], data=data)\n        return json_rsp\n\n    @staticmethod\n    async def request_fetchmedal():\n        inst = bilibili.instance\n        url = f'{base_url}/i/api/medal?page=1&pageSize=50'\n        json_rsp = await inst.bili_session_post(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def ReqWearingMedal():\n        inst = bilibili.instance\n        url = f'{base_url}/live_user/v1/UserInfo/get_weared_medal'\n        data = {\n            'uid': inst.dic_bilibili['uid'],\n            'csrf_token': ''\n        }\n        json_rsp = await inst.bili_session_post(url, data=data, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def ReqTitleInfo():\n        inst = bilibili.instance\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}'\n        sign = inst.calc_sign(temp_params)\n        url = f'{base_url}/appUser/myTitleList?{temp_params}&sign={sign}'\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n\n    @staticmethod\n    def request_getkey():\n        inst = bilibili.instance\n        url = 'https://passport.bilibili.com/api/oauth2/getKey'\n        temp_params = f'appkey={inst.dic_bilibili[\"appkey\"]}'\n        sign = inst.calc_sign(temp_params)\n        params = {'appkey': inst.dic_bilibili['appkey'], 'sign': sign}\n        response = inst.login_session_post(url, data=params)\n        return response\n\n    @staticmethod\n    def normal_login(username, password, captcha=None):\n        inst = bilibili.instance\n        if captcha is None:\n            captcha = ''\n        temp_params = f'actionKey={inst.dic_bilibili[\"actionKey\"]}&appkey={inst.dic_bilibili[\"appkey\"]}&build={inst.dic_bilibili[\"build\"]}&captcha={captcha}&device={inst.dic_bilibili[\"device\"]}&mobi_app={inst.dic_bilibili[\"mobi_app\"]}&password={password}&platform={inst.dic_bilibili[\"platform\"]}&username={username}'\n        sign = inst.calc_sign(temp_params)\n        payload = f'{temp_params}&sign={sign}'\n        url = \"https://passport.bilibili.com/api/v2/oauth2/login\"\n        response = inst.login_session_post(url, params=payload)\n        return response\n\n    @staticmethod\n    def get_captcha(username, password):\n        inst = bilibili.instance\n        \n        # with requests.Session() as s:\n        url = \"https://passport.bilibili.com/captcha\"\n        res = inst.login_session_get(url)\n        # print(res.content)\n        # print(res.content)\n\n        captcha = cnn_captcha(res.content)\n        return captcha\n        \n    @staticmethod\n    def request_check_token():\n        inst = bilibili.instance\n        list_url = f'access_key={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&ts={CurrentTime()}'\n        list_cookie = inst.dic_bilibili['cookie'].split(';')\n        params = ('&'.join(sorted(list_url.split('&') + list_cookie)))\n        sign = inst.calc_sign(params)\n        true_url = f'https://passport.bilibili.com/api/v2/oauth2/info?{params}&sign={sign}'\n        response1 = inst.login_session_get(true_url, headers=inst.dic_bilibili['appheaders'])\n        return response1\n\n    @staticmethod\n    def request_refresh_token():\n        inst = bilibili.instance\n        list_url = f'access_key={inst.dic_bilibili[\"access_key\"]}&access_token={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&refresh_token={inst.dic_bilibili[\"refresh_token\"]}&ts={CurrentTime()}'\n        list_cookie = inst.dic_bilibili['cookie'].split(';')\n        params = ('&'.join(sorted(list_url.split('&') + list_cookie)))\n        sign = inst.calc_sign(params)\n        payload = f'{params}&sign={sign}'\n        # print(payload)\n        url = f'https://passport.bilibili.com/api/v2/oauth2/refresh_token'\n        response1 = inst.login_session_post(url, headers=inst.dic_bilibili['appheaders'], params=payload)\n        return response1\n\n    @staticmethod\n    async def get_giftlist_of_storm(roomid):\n        inst = bilibili.instance\n        get_url = f\"{base_url}/lottery/v1/Storm/check?roomid={roomid}\"\n        json_rsp = await inst.bili_session_get(get_url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_gift_of_storm(id):\n        inst = bilibili.instance\n        storm_url = f'{base_url}/lottery/v1/Storm/join'\n        payload = {\n            \"id\": id,\n            \"color\": \"16777215\",\n            \"captcha_token\": \"\",\n            \"captcha_phrase\": \"\",\n            \"token\": \"\",\n            \"csrf_token\": inst.dic_bilibili['csrf']}\n        json_rsp = await inst.bili_session_post(storm_url, data=payload, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_gift_of_events_web(text1, text2, raffleid):\n        inst = bilibili.instance\n        headers = {\n            **(inst.dic_bilibili['pcheaders']),\n            'referer': text2\n            }\n        \n        pc_url = f'{base_url}/activity/v1/Raffle/join?roomid={text1}&raffleId={raffleid}'\n        json_rsp = await inst.bili_session_get(pc_url, headers=headers)\n\n        return json_rsp\n\n    @staticmethod\n    async def get_gift_of_events_app(text1, raffleid):\n        inst = bilibili.instance\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&actionKey={inst.dic_bilibili[\"actionKey\"]}&appkey={inst.dic_bilibili[\"appkey\"]}&build={inst.dic_bilibili[\"build\"]}&device={inst.dic_bilibili[\"device\"]}&event_type={raffleid}&mobi_app={inst.dic_bilibili[\"mobi_app\"]}&platform={inst.dic_bilibili[\"platform\"]}&room_id={text1}&ts={CurrentTime()}'\n        # params = temp_params + inst.dic_bilibili['app_secret']\n        sign = inst.calc_sign(temp_params)\n        true_url = f'{base_url}/YunYing/roomEvent?{temp_params}&sign={sign}'\n        json_rsp = await inst.bili_session_get(true_url, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n   \n    @staticmethod\n    async def get_gift_of_TV(real_roomid, TV_raffleid):\n        inst = bilibili.instance\n        url = f\"{base_url}/gift/v3/smalltv/join\"\n        payload = {\n            \"roomid\": real_roomid,\n            \"raffleId\": TV_raffleid,\n            \"type\": \"Gift\",\n            \"csrf_token\": ''\n            }\n            \n        json_rsp = await inst.bili_session_post(url, data=payload, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n        \n    @staticmethod\n    async def get_gift_of_TV_app(real_roomid, raffle_id, raffle_type):\n        inst = bilibili.instance\n        url = f\"{base_url}/gift/v4/smalltv/getAward\"\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&raffleId={raffle_id}&roomid={real_roomid}&ts={CurrentTime()}&type={raffle_type}'\n        sign = inst.calc_sign(temp_params)\n        payload = f'{temp_params}&sign={sign}'\n        # print(payload)\n        json_rsp = await inst.bili_session_post(url, params=payload, headers=inst.dic_bilibili['appheaders'])\n        # print(json_rsp)\n        return json_rsp\n        \n    @staticmethod\n    async def get_gift_of_guard(roomid, id):\n        inst = bilibili.instance\n        join_url = f\"{base_url}/lottery/v2/Lottery/join\"\n        data = {\n            'roomid': roomid,\n            'id': id,\n            'type': 'guard',\n            'csrf_token': inst.dic_bilibili['csrf']\n        }\n        json_rsp = await inst.bili_session_post(join_url, data=data, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_giftlist_of_events(text1):\n        inst = bilibili.instance\n        # url = f'{base_url}/activity/v1/Raffle/check?roomid={text1}'\n        temp_params = f'{base_url}/activity/v1/Common/mobileRoomInfo?access_key={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&roomid={text1}&ts={CurrentTime()}'\n        sign = inst.calc_sign(temp_params)\n        url = f'{base_url}/activity/v1/Common/mobileRoomInfo?{temp_params}&sign={sign}'\n        json_rsp = await bilibili.instance.bili_session_get(url, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_giftlist_of_TV(real_roomid):\n        inst = bilibili.instance\n        url = f\"{base_url}/gift/v3/smalltv/check?roomid={real_roomid}\"\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n        \n    @staticmethod\n    async def get_giftlist_of_guard(roomid):\n        inst = bilibili.instance\n        true_url = f'{base_url}/lottery/v1/Lottery/check_guard?roomid={roomid}'\n        json_rsp = await inst.bili_session_get(true_url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_activity_result(activity_roomid, activity_raffleid):\n        inst = bilibili.instance\n        url = f\"{base_url}/activity/v1/Raffle/notice?roomid={activity_roomid}&raffleId={activity_raffleid}\"\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_TV_result(TV_roomid, TV_raffleid):\n        inst = bilibili.instance\n        url = f\"{base_url}/gift/v3/smalltv/notice?type=small_tv&raffleId={TV_raffleid}\"\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def pcpost_heartbeat():\n        inst = bilibili.instance\n        url = f'{base_url}/User/userOnlineHeart'\n        json_rsp = await inst.bili_session_post(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    # 发送app心跳包\n    @staticmethod\n    async def apppost_heartbeat():\n        inst = bilibili.instance\n        time = CurrentTime()\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&ts={time}'\n        sign = inst.calc_sign(temp_params)\n        url = f'{base_url}/mobile/userOnlineHeart?{temp_params}&sign={sign}'\n        payload = {'roomid': 23058, 'scale': 'xhdpi'}\n        json_rsp = await inst.bili_session_post(url, data=payload, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n\n    # 心跳礼物\n    @staticmethod\n    async def heart_gift():\n        inst = bilibili.instance\n        url = f\"{base_url}/gift/v2/live/heart_gift_receive?roomid=3&area_v2_id=34\"\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_lotterylist(i):\n        inst = bilibili.instance\n        url = f\"{base_url}/lottery/v1/box/getStatus?aid={i}\"\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_gift_of_lottery(i, g):\n        inst = bilibili.instance\n        url1 = f'{base_url}/lottery/v1/box/draw?aid={i}&number={g + 1}'\n        json_rsp = await inst.bili_session_get(url1, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_time_about_silver():\n        inst = bilibili.instance\n        time = CurrentTime()\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&ts={time}'\n        sign = inst.calc_sign(temp_params)\n        GetTask_url = f'{base_url}/mobile/freeSilverCurrentTask?{temp_params}&sign={sign}'\n        json_rsp = await inst.bili_session_get(GetTask_url, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_silver(timestart, timeend):\n        inst = bilibili.instance\n        time = CurrentTime()\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&{inst.app_params}&time_end={timeend}&time_start={timestart}&ts={time}'\n        sign = inst.calc_sign(temp_params)\n        url = f'{base_url}/mobile/freeSilverAward?{temp_params}&sign={sign}'\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_dailybag():\n        inst = bilibili.instance\n        url = f'{base_url}/gift/v2/live/receive_daily_bag'\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_dosign():\n        inst = bilibili.instance\n        url = f'{base_url}/sign/doSign'\n        json_rsp = await inst.bili_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_dailytask():\n        inst = bilibili.instance\n        url = f'{base_url}/activity/v1/task/receive_award'\n        payload2 = {'task_id': 'double_watch_task'}\n        json_rsp = await inst.bili_session_post(url, data=payload2, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def get_grouplist():\n        inst = bilibili.instance\n        url = \"https://api.vc.bilibili.com/link_group/v1/member/my_groups\"\n        json_rsp = await inst.other_session_get(url, headers=inst.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def assign_group(i1, i2):\n        inst = bilibili.instance\n        temp_params = f'access_key={inst.dic_bilibili[\"access_key\"]}&actionKey={inst.dic_bilibili[\"actionKey\"]}&appkey={inst.dic_bilibili[\"appkey\"]}&build={inst.dic_bilibili[\"build\"]}&device={inst.dic_bilibili[\"device\"]}&group_id={i1}&mobi_app={inst.dic_bilibili[\"mobi_app\"]}&owner_id={i2}&platform={inst.dic_bilibili[\"platform\"]}&ts={CurrentTime()}'\n        sign = inst.calc_sign(temp_params)\n        url = f'https://api.vc.bilibili.com/link_setting/v1/link_setting/sign_in?{temp_params}&sign={sign}'\n        json_rsp = await inst.other_session_get(url, headers=inst.dic_bilibili['appheaders'])\n        return json_rsp\n\n    @staticmethod\n    async def gift_list():\n        url = f\"{base_url}/gift/v3/live/gift_config\"\n        res = await bilibili.instance.bili_session_get(url)\n        return res\n        \n    @staticmethod\n    async def req_realroomid(areaid):\n        url = f'{base_url}/room/v1/area/getRoomList?platform=web&parent_area_id={areaid}&cate_id=0&area_id=0&sort_type=online&page=1&page_size=30'\n        json_rsp = await bilibili.instance.bili_session_get(url)\n        return json_rsp\n     \n    @staticmethod\n    async def req_room_init(roomid):\n        url = f'{base_url}/room/v1/Room/room_init?id={roomid}'\n        json_rsp = await bilibili.instance.bili_session_get(url)\n        return json_rsp\n    \n    @staticmethod\n    async def ReqRoomInfo(roomid):\n        inst = bilibili.instance\n        url = f\"{base_url}/room/v1/Room/get_info?room_id={roomid}\"\n        res = await inst.bili_session_get(url)\n        return res\n\n    async def ReqGiveCoin2Av(self, video_id, num):\n        url = 'https://api.bilibili.com/x/web-interface/coin/add'\n        pcheaders = {\n            **(self.dic_bilibili['pcheaders']),\n            'referer': f'https://www.bilibili.com/video/av{video_id}'\n            }\n        data = {\n            'aid': video_id,\n            'multiply': num,\n            'cross_domain': 'true',\n            'csrf': self.dic_bilibili['csrf']\n        }\n        json_rsp = await self.other_session_post(url, headers=pcheaders, data=data)\n        return json_rsp\n\n    async def Heartbeat(self, aid, cid):\n        url = 'https://api.bilibili.com/x/report/web/heartbeat'\n        data = {'aid': aid, 'cid': cid, 'mid': self.dic_bilibili['uid'], 'csrf': self.dic_bilibili['csrf'],\n                'played_time': 0, 'realtime': 0,\n                'start_ts': int(time.time()), 'type': 3, 'dt': 2, 'play_type': 1}\n        json_rsp = await self.other_session_post(url, data=data, headers=self.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    async def ReqMasterInfo(self):\n        url = 'https://account.bilibili.com/home/reward'\n        json_rsp = await self.other_session_get(url, headers=self.dic_bilibili['pcheaders'])\n        return json_rsp\n\n    async def ReqVideoCid(self, video_aid):\n        url = f'https://www.bilibili.com/widget/getPageList?aid={video_aid}'\n        json_rsp = await self.other_session_get(url)\n        return json_rsp\n\n    async def DailyVideoShare(self, video_aid):\n        url = 'https://api.bilibili.com/x/web-interface/share/add'\n        data = {'aid': video_aid, 'jsonp': 'jsonp', 'csrf': self.dic_bilibili['csrf']}\n        json_rsp = await self.other_session_post(url, data=data, headers=self.dic_bilibili['pcheaders'])\n        return json_rsp\n    \n    async def req_fetch_uper_video(self, mid, page):\n        url = f'https://space.bilibili.com/ajax/member/getSubmitVideos?mid={mid}&pagesize=100&page={page}'\n        json_rsp = await self.other_session_get(url)\n        return json_rsp\n                \n    async def req_fetch_av(self):\n        text_tsp = await self.session_text_get('https://www.bilibili.com/ranking/all/0/0/1/')\n        return text_tsp\n    \n    async def req_vote_case(self, id, vote):\n        url = 'http://api.bilibili.com/x/credit/jury/vote'\n        payload = {\n            \"jsonp\": \"jsonp\",\n            \"cid\": id,\n            \"vote\": vote,\n            \"content\": \"\",\n            \"likes\": \"\",\n            \"hates\": \"\",\n            \"attr\": \"1\",\n            \"csrf\": ConfigLoader().dic_bilibili['csrf']\n        }\n        json_rsp = await self.other_session_post(url, headers=self.dic_bilibili['pcheaders'], data=payload)\n        return json_rsp\n        \n    async def req_fetch_case(self):\n        url = 'http://api.bilibili.com/x/credit/jury/caseObtain'\n        payload = {\n            \"jsonp\": \"jsonp\",\n            \"csrf\": ConfigLoader().dic_bilibili['csrf']\n        }\n        json_rsp = await self.other_session_post(url, headers=self.dic_bilibili['pcheaders'], data=payload)\n        return json_rsp\n        \n    async def req_check_voted(self, id):\n        headers = {\n            **(self.dic_bilibili['pcheaders']),\n            \"Referer\": f'https://www.bilibili.com/judgement/vote/{id}',\n            }\n        \n        url = f'https://api.bilibili.com/x/credit/jury/juryCase?jsonp=jsonp&callback=jQuery1720{randomint()}_{CurrentTime()}&cid={id}&_={CurrentTime()}'\n        text_rsp = await self.session_text_get(url, headers=headers)\n        # print(text_rsp)\n        return text_rsp\n"
  },
  {
    "path": "bilitimer.py",
    "content": "import asyncio\nimport time\nimport printer\n\n\ndef CurrentTime():\n    currenttime = int(time.time())\n    return currenttime\n\n\nclass BiliTimer:\n    __slots__ = ('loop',)\n    instance = None\n\n    def __new__(cls, loop=None):\n        if not cls.instance:\n            cls.instance = super(BiliTimer, cls).__new__(cls)\n            cls.instance.loop = loop\n        return cls.instance\n    \n    def excute_async(self, i):\n        print('执行', i)\n        asyncio.ensure_future(i[0](*i[1]))\n      \n    @staticmethod\n    def call_after(func, delay):\n        inst = BiliTimer.instance\n        value = (func, ())\n        inst.loop.call_later(delay, inst.excute_async, value)\n        \n    @staticmethod\n    def append2list_jobs(func, time_expected, tuple_values):\n        inst = BiliTimer.instance\n        current_time = CurrentTime()\n        value = (func, tuple_values)\n        inst.loop.call_later(time_expected-current_time, inst.excute_async, value)\n    \n"
  },
  {
    "path": "conf/bilibili.toml",
    "content": "appkey = \"1d8b6e7d45233436\"\nactionKey = \"appkey\"\nbuild = \"520001\"\ndevice = \"android\"\nmobi_app = \"android\"\nplatform = \"android\"\napp_secret = \"560c52ccd288fed045859ed18bffd973\"\nrefresh_token = \"\"\naccess_key = \"\"\ncookie = \"\"\ncsrf = \"\"\nuid = \"\"\n\n[pcheaders]\nAccept = \"application/json, text/plain, */*\"\nUser-Agent = \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36\"\nAccept-Language = \"zh-CN,zh;q=0.9\"\naccept-encoding = \"gzip, deflate\"\ncookie = \"\"\n\n[appheaders]\nUser-Agent = \"bili-universal/6570 CFNetwork/894 Darwin/17.4.0\"\nAccept-encoding = \"gzip\"\nBuvid = \"000ce0b9b9b4e342ad4f421bcae5e0ce\"\nDisplay-ID = \"146771405-1521008435\"\nAccept-Language = \"zh-CN\"\nAccept = \"text/html,application/xhtml+xml,*/*;q=0.8\"\nConnection = \"keep-alive\"\ncookie = \"\"\n\n[account]\nusername = \"\"\npassword = \"\"\n\n[saved-session]\naccess_key = \"\"\ncookie = \"\"\ncsrf = \"\"\nuid = \"\"\nrefresh_token = \"\"\n"
  },
  {
    "path": "conf/color.toml",
    "content": "[user-level]\nul0 = \"#646c7a\"\nul1 = \"#969696\"\nul2 = \"#969696\"\nul3 = \"#969696\"\nul4 = \"#969696\"\nul5 = \"#969696\"\nul6 = \"#969696\"\nul7 = \"#969696\"\nul8 = \"#969696\"\nul9 = \"#969696\"\nul10 = \"#969696\"\nul11 = \"#61c05a\"\nul12 = \"#61c05a\"\nul13 = \"#61c05a\"\nul14 = \"#61c05a\"\nul15 = \"#61c05a\"\nul16 = \"#61c05a\"\nul17 = \"#61c05a\"\nul18 = \"#61c05a\"\nul19 = \"#61c05a\"\nul20 = \"#61c05a\"\nul21 = \"#5896de\"\nul22 = \"#5896de\"\nul23 = \"#5896de\"\nul24 = \"#5896de\"\nul25 = \"#5896de\"\nul26 = \"#5896de\"\nul27 = \"#5896de\"\nul28 = \"#5896de\"\nul29 = \"#5896de\"\nul30 = \"#5896de\"\nul31 = \"#a068f1\"\nul32 = \"#a068f1\"\nul33 = \"#a068f1\"\nul34 = \"#a068f1\"\nul35 = \"#a068f1\"\nul36 = \"#a068f1\"\nul37 = \"#a068f1\"\nul38 = \"#a068f1\"\nul39 = \"#a068f1\"\nul40 = \"#a068f1\"\nul41 = \"#ff86b2\"\nul42 = \"#ff86b2\"\nul43 = \"#ff86b2\"\nul44 = \"#ff86b2\"\nul45 = \"#ff86b2\"\nul46 = \"#ff86b2\"\nul47 = \"#ff86b2\"\nul48 = \"#ff86b2\"\nul49 = \"#ff86b2\"\nul50 = \"#ff86b2\"\nul51 = \"#ff9f3d\"\nul52 = \"#ff9f3d\"\nul53 = \"#ff9f3d\"\nul54 = \"#ff9f3d\"\nul55 = \"#ff9f3d\"\nul56 = \"#ff9f3d\"\nul57 = \"#ff9f3d\"\nul58 = \"#ff9f3d\"\nul59 = \"#ff9f3d\"\nul60 = \"#ff9f3d\"\n\n[fans-level]\nfl1 = \"#61ddcb\"\nfl2 = \"#61ddcb\"\nfl3 = \"#61ddcb\"\nfl4 = \"#61ddcb\"\nfl5 = \"#5896de\"\nfl6 = \"#5896de\"\nfl7 = \"#5896de\"\nfl8 = \"#5896de\"\nfl9 = \"#a068f1\"\nfl10 = \"#a068f1\"\nfl11 = \"#a068f1\"\nfl12 = \"#a068f1\"\nfl13 = \"#ff86b2\"\nfl14 = \"#ff86b2\"\nfl15 = \"#ff86b2\"\nfl16 = \"#ff86b2\"\nfl17 = \"#f6be18\"\nfl18 = \"#f6be18\"\nfl19 = \"#f6be18\"\nfl20 = \"#f6be18\"\n\n[others]\nvip = [ 255, 94, 144,]\nsvip = [ 255, 208, 0,]\nadmin = \"#ea9336\"\ndefault_name = \"#808080\"\n"
  },
  {
    "path": "conf/title.toml",
    "content": "title-176-1 = \"凯旋\"\ntitle-175-1 = \"骑士之心\"\ntitle-175-2 = \"永恒誓约\"\ntitle-174-1 = \"幻影\"\ntitle-174-2 = \"光之护卫\"\ntitle-173-1 = \"预言家\"\ntitle-172-1 = \"黎明之光\"\ntitle-171-1 = \"蔷薇之冠\"\ntitle-170-1 = \"星月之梦\"\ntitle-169-1 = \"修仙 \"\ntitle-168-1 = \"舒服\"\ntitle-167-1 = \"rhythm saber \"\ntitle-166-1 = \"cantus knight\"\ntitle-165-1 = \"PK活动用户周榜头衔\"\ntitle-164-1 = \"PK主播头衔\"\ntitle-163-1 = \"首席应援\"\ntitle-162-1 = \"枸杞牛奶\"\ntitle-161-1 = \"审判官\"\ntitle-160-1 = \"天秀凉皇\"\ntitle-159-1 = \"王蜀黍\"\ntitle-155-1 = \"初号机\"\ntitle-157-1 = \"吃瓜群众\"\ntitle-156-1 = \"一本满足\"\ntitle-154-1 = \"为爱而生\"\ntitle-153-1 = \"1号玩家\"\ntitle-153-2 = \"荣耀之巅\"\ntitle-152-1 = \"大冒险家\"\ntitle-151-1 = \"全靠浪\"\ntitle-150-1 = \"甜蜜双排\"\ntitle-149-1 = \"大吉大利\"\ntitle-148-1 = \"头号歌迷\"\ntitle-147-1 = \"英雄联盟LPL2018助威\"\ntitle-146-1 = \"理事长\"\ntitle-145-1 = \"桃仙\"\ntitle-144-1 = \"一见倾心\"\ntitle-144-2 = \"花前月下\"\ntitle-143-1 = \"红线仙\"\ntitle-142-1 = \"喜气之王\"\ntitle-141-1 = \"在下福了\"\ntitle-140-1 = \"秋田君\"\ntitle-140-2 = \"年兽克星\"\ntitle-139-1 = \"雷狮海盗团\"\ntitle-138-1 = \"总选之王\"\ntitle-137-1 = \"一缺三\"\ntitle-136-1 = \"老哥稳\"\ntitle-135-1 = \"为所欲为\"\ntitle-134-1 = \"全场最佳\"\ntitle-134-2 = \"王者之证\"\ntitle-133-1 = \"一叶知秋\"\ntitle-131-1 = \"太阳骑士\"\ntitle-131-2 = \"天选之人\"\ntitle-130-1 = \"镜花水月\"\ntitle-129-1 = \"风花雪月\"\ntitle-128-1 = \"青葱岁月\"\ntitle-128-2 = \"唯望君安\"\ntitle-127-1 = \"自学高手\"\ntitle-127-2 = \"白学大师\"\ntitle-126-1 = \"绚烂夏花\"\ntitle-126-2 = \"荷塘月色\"\ntitle-125-1 = \"在此饶舌\"\ntitle-124-1 = \"大队长\"\ntitle-123-1 = \"一般社员\"\ntitle-123-2 = \"执行委员\"\ntitle-122-1 = \"岁月如歌\"\ntitle-121-1 = \"百战雄狮\"\ntitle-120-1 = \"门庭若市\"\ntitle-119-1 = \"五魁首\"\ntitle-118-1 = \"冒险家\"\ntitle-117-1 = \"圣骑士\"\ntitle-116-1 = \"庇护之光\"\ntitle-115-1 = \"终极应援\"\ntitle-114-1 = \"高级应援\"\ntitle-113-1 = \"初级应援\"\ntitle-112-1 = \"旅人\"\ntitle-111-1 = \"bilibili Link\"\ntitle-110-1 = \"征服王\"\ntitle-109-1 = \"征服者\"\ntitle-108-1 = \"演武者\"\ntitle-108-2 = \"武神\"\ntitle-107-1 = \"神圣\"\ntitle-106-1 = \"骑士\"\ntitle-105-1 = \"神州\"\ntitle-104-1 = \"蒸汽\"\ntitle-103-1 = \"神圣\"\ntitle-102-1 = \"骑士\"\ntitle-101-1 = \"神州\"\ntitle-100-1 = \"蒸汽\"\ntitle-99-1 = \"神谕阐释者\"\ntitle-98-1 = \"至高骑士\"\ntitle-97-1 = \"无上至尊\"\ntitle-96-1 = \"神曲终焉\"\ntitle-95-1 = \"丘比特\"\ntitle-95-2 = \"维纳斯\"\ntitle-94-1 = \"酋长\"\ntitle-93-1 = \"注孤身\"\ntitle-92-1 = \"年兽抱回家\"\ntitle-91-1 = \"灶神\"\ntitle-90-1 = \"财神爷\"\ntitle-89-1 = \"爆竹\"\ntitle-89-2 = \"意大利炮\"\ntitle-88-1 = \"不负初心\"\ntitle-87-1 = \"四季老\"\ntitle-86-1 = \"季老\"\ntitle-85-1 = \"孜孜不倦\"\ntitle-84-1 = \"水滴石穿\"\ntitle-83-1 = \"功成名就\"\ntitle-82-1 = \"御守\"\ntitle-82-2 = \"满分御守\"\ntitle-82-3 = \"桃花御守\"\ntitle-81-1 = \"新年快乐\"\ntitle-80-1 = \"Santa Claus\"\ntitle-79-1 = \"FFF团长\"\ntitle-78-1 = \"FFF团员\"\ntitle-77-1 = \"Miss·椛\"\ntitle-76-1 = \"理事长\"\ntitle-75-1 = \"见习舰长\"\ntitle-75-2 = \"代理提督\"\ntitle-75-3 = \"名誉总督\"\ntitle-74-1 = \"SuperStar\"\ntitle-73-1 = \"SuperStar\"\ntitle-72-1 = \"SuperStar\"\ntitle-71-1 = \"SuperStar\"\ntitle-70-1 = \"SuperStar\"\ntitle-69-1 = \"Star\"\ntitle-68-1 = \"Star\"\ntitle-67-1 = \"Star\"\ntitle-66-1 = \"Star\"\ntitle-65-1 = \"Star\"\ntitle-64-1 = \"応援\"\ntitle-63-1 = \"応援\"\ntitle-62-1 = \"応援\"\ntitle-61-1 = \"吃瓜群众\"\ntitle-60-1 = \"百鬼夜行\"\ntitle-59-1 = \"一本满足\"\ntitle-58-1 = \"盛夏花火\"\ntitle-57-1 = \"金闪闪\"\ntitle-56-1 = \"红叶祭\"\ntitle-56-2 = \"栖霞红枫\"\ntitle-56-3 = \"香山黄栌\"\ntitle-56-4 = \"秋之回忆\"\ntitle-55-1 = \"全是套路\"\ntitle-54-1 = \"暖心\"\ntitle-53-1 = \"神七\"\ntitle-52-1 = \"高手\"\ntitle-51-1 = \"大神\"\ntitle-50-1 = \"钻石王老五\"\ntitle-49-1 = \"绝对零度\"\ntitle-48-1 = \"钻石星尘\"\ntitle-47-1 = \"电视王\"\ntitle-46-1 = \"甘sugiru\"\ntitle-45-1 = \"砂糖战士\"\ntitle-44-1 = \"甜党\"\ntitle-43-1 = \"咸鱼皇\"\ntitle-42-1 = \"咸蛋超人\"\ntitle-41-1 = \"咸党\"\ntitle-40-1 = \"甜咸无双\"\ntitle-39-1 = \"七周年\"\ntitle-38-1 = \"超耐久\"\ntitle-37-1 = \"久负盛名\"\ntitle-36-1 = \"方得始终\"\ntitle-35-1 = \"关灯\"\ntitle-34-1 = \"起来嗨\"\ntitle-33-1 = \"被窝\"\ntitle-32-1 = \"菠菜\"\ntitle-30-1 = \"追云逐月\"\ntitle-29-1 = \"度年如日\"\ntitle-28-1 = \"姹紫嫣红\"\ntitle-27-1 = \"唱见精灵\"\ntitle-26-1 = \"唱见天使\"\ntitle-25-1 = \"唱见神话\"\ntitle-24-1 = \"甜心精灵\"\ntitle-23-1 = \"甜心天使\"\ntitle-22-1 = \"甜心神话\"\ntitle-21-1 = \"旅人\"\ntitle-20-1 = \"冒险家\"\ntitle-19-1 = \"圣骑士\"\ntitle-18-1 = \"庇护之光\"\ntitle-17-1 = \"月老\"\ntitle-16-1 = \"资深老司机\"\ntitle-15-1 = \"校长\"\ntitle-14-1 = \"教导主任\"\ntitle-13-1 = \"班主任\"\ntitle-12-1 = \"辅导员\"\ntitle-11-1 = \"雪亲王\"\ntitle-10-1 = \"圣尼古拉斯\"\ntitle-9-1 = \"真圣诞爸爸\"\ntitle-8-1 = \"圣诞小天使\"\ntitle-7-1 = \"圣诞青年\"\ntitle-6-1 = \"圣诞中年人\"\ntitle-5-1 = \"圣诞老人\"\ntitle-4-1 = \"超年糕团长\"\ntitle-3-1 = \"年糕团长\"\ntitle-2-1 = \"年糕团\"\ntitle-1-1 = \"糯米粉\"\n"
  },
  {
    "path": "conf/title_init.py",
    "content": "import requests\nimport toml\n\n\nrsp = requests.get('https://api.live.bilibili.com/rc/v1/Title/webTitles')\nrsp.encoding = 'utf-8'\njson_rsp = rsp.json()\ndata = json_rsp['data']\ndict_title = {i['identification']: i['name'] for i in data}\n    \nwith open('title.toml', 'w', encoding=\"utf-8\") as f:\n    toml.dump(dict_title, f)\n\n\n"
  },
  {
    "path": "conf/user.toml",
    "content": "[print_control]\ndanmu = false\ndebug = false\n\n[task_control]\n# 清理即将过期礼物，请true之后一定要把紧随其后的room设置为真实房间号\nclean-expiring-gift = false\n# 单位秒\nset-expiring-time = 43200\n# 对过期礼物是否先投递到其他勋章(按照勋章等级投递)，之后会剩余的清理掉roomid里面\nclean_expiring_gift2all_medal = false\nclean-expiring-gift2room = 0\n\n# 一天最多一个硬币兑换机会\nsilver2coin = false\n\n# 自动投满佩戴勋章当日亲密度\nsend2wearing-medal = false\n# 房间号 短房间 \nsend2medal = []\n\n# 老接口高倍率兑换硬币为银瓜子，现已失效，请勿修改！！\ndoublegain_coin2silver = false\n\n# 输入数字 0-5 表示主站自动投币\ngivecoin = 0\n# 投币av获取(bilitop或者uper)分别代表b站随机或者根据up主mid选取\nfetchrule = \"bilitop\"\n# up主list([123]或者[123, 234, 123]等)\nmid = [207539637]\n\n\n[other_control]\n# 保持连接状态，下次再登陆不会重复登陆，读取存储的cookie重用，如要密码登陆，请手动清除bilibili.conf里面的cookie\nkeep-login = true\n\n# 默认监听房间号(打印弹幕)\ndefault_monitor_roomid = 23058\n\n# 额外自定义弹幕监控房间\nraffle_minitor_roomid = 0\n\n# raffle monitor(控制抽奖监控的，默认一个分区一个监控)\narea_ids = [1, 2, 3, 4, 5]\n"
  },
  {
    "path": "configloader.py",
    "content": "import toml\n\n\n# \"#969696\"\ndef hex_to_rgb_percent(hex_str):\n    return tuple(int(n, 16)/255 for n in (hex_str[1:3], hex_str[3:5], hex_str[5:7]))\n\n\n# [255 255 255]\ndef rgb_to_percent(rgb_list):\n    return rgb_list[0]/255, rgb_list[1]/255, rgb_list[2]/255\n    \n    \nclass ConfigLoader():\n    \n    instance = None\n\n    def __new__(cls, fileDir=None):\n        if not cls.instance:\n            cls.instance = super(ConfigLoader, cls).__new__(cls)\n            \n            colorfile = f'{fileDir}/conf/color.toml'\n            userfile = f'{fileDir}/conf/user.toml'\n            bilibilifile = f'{fileDir}/conf/bilibili.toml'\n            titlefile = f'{fileDir}/conf/title.toml'\n            \n            cls.instance.colorfile = colorfile\n            cls.instance.dic_color = cls.instance.load_color()\n            # print(cls.instance.dic_color)\n            \n            cls.instance.userfile = userfile\n            cls.instance.dic_user = cls.instance.load_user()\n            # print(cls.instance.dic_user)\n            \n            cls.instance.bilibilifile = bilibilifile\n            cls.instance.dic_bilibili = cls.instance.load_bilibili()\n            # print(cls.instance.dic_bilibili)\n            \n            cls.instance.titlefile = titlefile\n            cls.instance.dic_title = cls.instance.load_title()\n            print(\"# 初始化完成\")\n        return cls.instance\n    \n    def write2bilibili(self, dic):\n        with open(self.bilibilifile, encoding=\"utf-8\") as f:\n            dic_bilibili = toml.load(f)\n        for i in dic.keys():\n            dic_bilibili['saved-session'][i] = dic[i]\n        with open(self.bilibilifile, 'w', encoding=\"utf-8\") as f:\n            toml.dump(dic_bilibili, f)\n            \n    def load_bilibili(self):\n        with open(self.bilibilifile, encoding=\"utf-8\") as f:\n            dic_bilibili = toml.load(f)\n        if not dic_bilibili['account']['username']:\n            username = input(\"# 输入帐号: \")\n            password = input(\"# 输入密码: \")\n            dic_bilibili['account']['username'] = username\n            dic_bilibili['account']['password'] = password\n            with open(self.bilibilifile, 'w', encoding=\"utf-8\") as f:\n                toml.dump(dic_bilibili, f)\n                \n        return dic_bilibili\n                \n    def load_color(self):\n        with open(self.colorfile, encoding=\"utf-8\") as f:\n            dic_color = toml.load(f)\n        for i in dic_color.values():\n            for j in i.keys():\n                if isinstance(i[j], str):\n                    i[j] = hex_to_rgb_percent(i[j])\n                else:\n                    i[j] = rgb_to_percent(i[j])\n                        \n        return dic_color\n                        \n    def load_user(self):\n        with open(self.userfile, encoding=\"utf-8\") as f:\n            dic_user = toml.load(f)\n        return dic_user\n        \n    def load_title(self):\n        with open(self.titlefile, encoding=\"utf-8\") as f:\n            dic_title = toml.load(f)\n        return dic_title\n        \n\n    \n    \n        \n        \n            \n       \n        \n\n\n"
  },
  {
    "path": "connect.py",
    "content": "import asyncio\nimport utils\nimport danmu\nimport printer\nfrom online_net import OnlineNet\nfrom configloader import ConfigLoader\nimport random\n\n \nasync def get_one(areaid):\n    # 1 娱乐分区, 2 游戏分区, 3 手游分区, 4 绘画分区\n    if areaid == 1:\n        roomid = 23058\n        if (await utils.check_room_for_danmu(roomid, areaid)):\n            printer.info([f'{areaid}号弹幕监控选择房间（{roomid}）'], True)\n            return roomid\n            \n    while True:\n        json_rsp = await OnlineNet().req('req_realroomid', areaid)\n        data = json_rsp['data']\n        if not data:\n            await asyncio.sleep(3)\n            printer.warn(json_rsp)\n            continue\n        roomid = random.choice(data)['roomid']\n        if (await utils.check_room_for_danmu(roomid, areaid)):\n            printer.info([f'{areaid}号弹幕监控选择房间（{roomid}）'], True)\n            return roomid\n\n\nclass connect():\n    __slots__ = ('danmuji', 'room_id', 'area_id')\n    instance = None\n    \n    def __new__(cls, *args, **kw):\n        if not cls.instance:\n            cls.instance = super(connect, cls).__new__(cls, *args, **kw)\n            cls.instance.danmuji = None\n            cls.instance.room_id = 0\n            cls.instance.area_id = -1\n        return cls.instance\n        \n    async def run(self):\n        self.room_id = ConfigLoader().dic_user['other_control']['default_monitor_roomid']\n        self.danmuji = danmu.DanmuPrinter(self.room_id, self.area_id)\n        time_now = 0\n        while True:\n            if int(utils.CurrentTime()) - time_now <= 3:\n                printer.info(['当前网络不稳定，弹幕监控将自动延迟3秒后重启'], True)\n                await asyncio.sleep(3)\n            printer.info(['正在启动直播监控弹幕姬'], True)\n            time_now = int(utils.CurrentTime())\n            connect_results = await self.danmuji.open()\n            if not connect_results:\n                continue\n            task_main = asyncio.ensure_future(self.danmuji.read_datas())\n            task_heartbeat = asyncio.ensure_future(self.danmuji.heart_beat())\n            tasks = [task_main, task_heartbeat]\n            finished, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)\n            printer.info(['主弹幕姬异常或主动断开，正在处理剩余信息'], True)\n            if not task_heartbeat.done():\n                task_heartbeat.cancel()\n            await self.danmuji.close()\n            await asyncio.wait(pending)\n            printer.info(['主弹幕姬退出，剩余任务处理完毕'], True)\n    \n    @staticmethod\n    async def reconnect(roomid):\n        ConfigLoader().dic_user['other_control']['default_monitor_roomid'] = roomid\n        print('已经切换roomid')\n        if connect.instance.danmuji is not None:\n            connect.instance.danmuji.room_id = roomid\n            await connect.instance.danmuji.close()\n        \n        \nclass RaffleConnect():\n    def __init__(self, areaid):\n        self.danmuji = None\n        self.roomid = 0\n        self.areaid = areaid\n        \n    async def run(self):\n        self.danmuji = danmu.DanmuRaffleHandler(self.roomid, self.areaid)\n        time_now = 0\n        while True:\n            if int(utils.CurrentTime()) - time_now <= 3:\n                printer.info(['当前网络不稳定，弹幕监控将自动延迟3秒后重启'], True)\n                await asyncio.sleep(3)\n            self.danmuji.room_id = await get_one(self.areaid)\n            printer.info(['正在启动抽奖监控弹幕姬'], True)\n            time_now = int(utils.CurrentTime())\n            connect_results = await self.danmuji.open()\n            if not connect_results:\n                continue\n            task_main = asyncio.ensure_future(self.danmuji.read_datas())\n            task_heartbeat = asyncio.ensure_future(self.danmuji.heart_beat())\n            task_checkarea = asyncio.ensure_future(self.danmuji.check_area())\n            tasks = [task_main, task_heartbeat, task_checkarea]\n            finished, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)\n            printer.info([f'{self.areaid}号弹幕姬异常或主动断开，正在处理剩余信息'], True)\n            if not task_heartbeat.done():\n                task_heartbeat.cancel()\n            if not task_checkarea.done():\n                task_checkarea.cancel()\n            await self.danmuji.close()\n            await asyncio.wait(pending)\n            printer.info([f'{self.areaid}号弹幕姬退出，剩余任务处理完毕'], True)\n                \n                \nclass YjConnection():\n    def __init__(self):\n        self.danmuji = None\n        self.roomid = 0\n        self.areaid = 0\n        \n    async def run(self):\n        self.roomid = ConfigLoader().dic_user['other_control']['raffle_minitor_roomid']\n        if not self.roomid:\n            return\n        self.danmuji = danmu.YjMonitorHandler(self.roomid, self.areaid)\n        time_now = 0\n        while True:\n            if int(utils.CurrentTime()) - time_now <= 3:\n                printer.info(['当前网络不稳定，弹幕监控将自动延迟3秒后重启'], True)\n                await asyncio.sleep(3)\n            printer.info(['正在启动Yj监控弹幕姬'], True)\n            time_now = int(utils.CurrentTime())\n            connect_results = await self.danmuji.open()\n            if not connect_results:\n                continue\n            task_main = asyncio.ensure_future(self.danmuji.read_datas())\n            task_heartbeat = asyncio.ensure_future(self.danmuji.heart_beat())\n            tasks = [task_main, task_heartbeat]\n            finished, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)\n            printer.info(['Yj弹幕姬异常或主动断开，正在处理剩余信息'], True)\n            if not task_heartbeat.done():\n                task_heartbeat.cancel()\n            await self.danmuji.close()\n            await asyncio.wait(pending)\n            printer.info(['Yj弹幕姬退出，剩余任务处理完毕'], True)\n            \n            \n\n        \n                    \n"
  },
  {
    "path": "danmu.py",
    "content": "from statistics import Statistics\nimport printer\nimport rafflehandler\nimport utils\nimport asyncio\nimport struct\nimport json\nimport sys\nimport aiohttp\n                                                          \n\nclass BaseDanmu():\n    structer = struct.Struct('!I2H2I')\n\n    def __init__(self, room_id, area_id):\n        self.client = aiohttp.ClientSession()\n        self._area_id = area_id\n        self.room_id = room_id\n        self._bytes_heartbeat = self._wrap_str(opt=2, body='')\n    \n    @property\n    def room_id(self):\n        # 仅仅为了借用roomi_id.setter，故不设置\n        pass\n        \n    @room_id.setter\n    def room_id(self, room_id):\n        self._room_id = room_id\n        str_conn_room = f'{{\"uid\":0,\"roomid\":{room_id},\"protover\":1,\"platform\":\"web\",\"clientver\":\"1.3.3\"}}'\n        self._bytes_conn_room = self._wrap_str(opt=7, body=str_conn_room)\n        \n    def _wrap_str(self, opt, body, len_header=16, ver=1, seq=1):\n        remain_data = body.encode('utf-8')\n        len_data = len(remain_data) + len_header\n        header = self.structer.pack(len_data, len_header, ver, opt, seq)\n        data = header + remain_data\n        return data\n\n    async def _send_bytes(self, bytes_data):\n        try:\n            await self.ws.send_bytes(bytes_data)\n        except asyncio.CancelledError:\n            return False\n        except:\n            print(sys.exc_info()[0], sys.exc_info()[1])\n            return False\n        return True\n\n    async def _read_bytes(self):\n        bytes_data = None\n        try:\n            # 如果调用aiohttp的bytes read，none的时候，会raise exception\n            msg = await asyncio.wait_for(self.ws.receive(), timeout=35.0)\n            bytes_data = msg.data\n        except asyncio.TimeoutError:\n            print('# 由于心跳包30s一次，但是发现35内没有收到任何包，说明已经悄悄失联了，主动断开')\n            return None\n        except:\n            print(sys.exc_info()[0], sys.exc_info()[1])\n            print('请联系开发者')\n            return None\n        \n        return bytes_data\n        \n    async def open(self):\n        try:\n            url = 'wss://broadcastlv.chat.bilibili.com:443/sub'\n            self.ws = await asyncio.wait_for(self.client.ws_connect(url), timeout=3)\n        except:\n            print(\"# 连接无法建立，请检查本地网络状况\")\n            print(sys.exc_info()[0], sys.exc_info()[1])\n            return False\n        printer.info([f'{self._area_id}号弹幕监控已连接b站服务器'], True)\n        return (await self._send_bytes(self._bytes_conn_room))\n        \n    async def heart_beat(self):\n        try:\n            while True:\n                if not (await self._send_bytes(self._bytes_heartbeat)):\n                    return\n                await asyncio.sleep(30)\n        except asyncio.CancelledError:\n            pass\n            \n    async def read_datas(self):\n        while True:\n            datas = await self._read_bytes()\n            # 本函数对bytes进行相关操作，不特别声明，均为bytes\n            if datas is None:\n                return\n            data_l = 0\n            len_datas = len(datas)\n            while data_l != len_datas:\n                # 每片data都分为header和body，data和data可能粘连\n                # data_l == header_l && next_data_l = next_header_l\n                # ||header_l...header_r|body_l...body_r||next_data_l...\n                tuple_header = self.structer.unpack_from(datas[data_l:])\n                len_data, len_header, ver, opt, seq = tuple_header\n                body_l = data_l + len_header\n                next_data_l = data_l + len_data\n                body = datas[body_l:next_data_l]\n                # 人气值(或者在线人数或者类似)以及心跳\n                if opt == 3:\n                    # UserCount, = struct.unpack('!I', remain_data)\n                    printer.debug(f'弹幕心跳检测{self._area_id}')\n                # cmd\n                elif opt == 5:\n                    if not self.handle_danmu(body):\n                        return\n                # 握手确认\n                elif opt == 8:\n                    printer.info([f'{self._area_id}号弹幕监控进入房间（{self._room_id}）'], True)\n                else:\n                    printer.warn(datas[data_l:next_data_l])\n\n                data_l = next_data_l\n\n    # 待确认\n    async def close(self):\n        try:\n            await self.ws.close()\n        except:\n            print('请联系开发者', sys.exc_info()[0], sys.exc_info()[1])\n        if not self.ws.closed:\n            printer.info([f'请联系开发者  {self._area_id}号弹幕收尾模块状态{self.ws.closed}'], True)\n                \n    def handle_danmu(self, body):\n        return True\n                \n                \nclass DanmuPrinter(BaseDanmu):\n    def handle_danmu(self, body):\n        dic = json.loads(body.decode('utf-8'))\n        cmd = dic['cmd']\n        # print(cmd)\n        if cmd == 'DANMU_MSG':\n            # print(dic)\n            printer.print_danmu(dic)\n        return True\n\n        \nclass DanmuRaffleHandler(BaseDanmu):\n    async def check_area(self):\n        try:\n            while True:\n                is_ok = await asyncio.shield(utils.check_room_for_danmu(self._room_id, self._area_id))\n                if not is_ok:\n                    printer.info([f'{self._room_id}不再适合作为监控房间，即将切换'], True)\n                    return\n                await asyncio.sleep(300)\n        except asyncio.CancelledError:\n            pass\n        \n    def handle_danmu(self, body):\n        dic = json.loads(body.decode('utf-8'))\n        cmd = dic['cmd']\n        \n        if cmd == 'PREPARING':\n            printer.info([f'{self._area_id}号弹幕监控房间下播({self._room_id})'], True)\n            return False\n    \n        elif cmd == 'NOTICE_MSG':\n            # 1 《第五人格》哔哩哔哩直播预选赛六强诞生！\n            # 2 全区广播：<%user_name%>送给<%user_name%>1个嗨翻全城，快来抽奖吧\n            # 3 <%user_name%> 在 <%user_name%> 的房间开通了总督并触发了抽奖，点击前往TA的房间去抽奖吧\n            # 4 欢迎 <%总督 user_name%> 登船\n            # 5 恭喜 <%user_name%> 获得大奖 <%23333x银瓜子%>, 感谢 <%user_name%> 的赠送\n            # 6 <%user_name%> 在直播间 <%529%> 使用了 <%20%> 倍节奏风暴，大家快去跟风领取奖励吧！(只报20的)\n            # 8 全区广播：主播<%红莉栖魔王喵%>开启了“任意门”，点击前往TA的房间去抽奖吧！\n            msg_type = dic['msg_type']\n            msg_common = dic['msg_common']\n            real_roomid = dic['real_roomid']\n            msg_common = dic['msg_common'].replace(' ', '')\n            msg_common = msg_common.replace('”', '')\n            msg_common = msg_common.replace('“', '')\n            if msg_type == 2 or msg_type == 8:\n                str_gift = msg_common.split('%>')[-1].split('，')[0]\n                if '个' in str_gift:\n                    raffle_num, raffle_name = str_gift.split('个')\n                elif '了' in str_gift:\n                    raffle_num = 1\n                    raffle_name = str_gift.split('了')[-1]\n                else:\n                    raffle_num = 1\n                    raffle_name = str_gift\n                broadcast = msg_common.split('广播')[0]\n                printer.info([f'{self._area_id}号弹幕监控检测到{real_roomid:^9}的{raffle_name}'], True)\n                rafflehandler.Rafflehandler.Put2Queue((real_roomid,), rafflehandler.handle_1_room_TV)\n                broadcast_type = 0 if broadcast == '全区' else 1\n                Statistics.add2pushed_raffle(raffle_name, broadcast_type)\n            elif msg_type == 3:\n                raffle_name = msg_common.split('开通了')[-1][:2]\n                printer.info([f'{self._area_id}号弹幕监控检测到{real_roomid:^9}的{raffle_name}'], True)\n                rafflehandler.Rafflehandler.Put2Queue((real_roomid,), rafflehandler.handle_1_room_guard)\n                broadcast_type = 0 if raffle_name == '总督' else 2\n                Statistics.add2pushed_raffle(raffle_name, broadcast_type)\n            elif msg_type == 6:\n                raffle_name = '二十倍节奏风暴'\n                printer.info([f'{self._area_id}号弹幕监控检测到{real_roomid:^9}的{raffle_name}'], True)\n                rafflehandler.Rafflehandler.Put2Queue((real_roomid,), rafflehandler.handle_1_room_storm)\n                Statistics.add2pushed_raffle(raffle_name)\n        \n        return True\n            \n        \nclass YjMonitorHandler(BaseDanmu):\n    def __init__(self, room_id, area_id):\n        super().__init__(room_id, area_id)\n        keys = '阝飠牜饣卩卪厸厶厽孓宀巛巜彳廴彡彐忄扌攵氵灬爫犭疒癶礻糹纟罒罓耂虍訁覀兦亼亽亖亗吂卝匸皕旡玊尐幵朩囘囙囜囝囟囡団囤囥囦囧囨囩囪囫囬囮囯困囱囲図囵囶囷囸囹固囻囼图囿圀圁圂圃圄圅圆圇圉圊圌圍圎圏圐圑園圓圔圕圖圗團圙圚圛圜圝圞'\n        self.__reverse_keys = {value: i for i, value in enumerate(keys)}\n        self.__read = {}\n    \n    def __base2dec(self, str_num, base=110):\n        result = 0\n        for i in str_num:\n            result = result * base + self.__reverse_keys[i]\n        return result\n    \n    def __reverse(self, msg):\n        msg = msg.replace('?', '')\n        first = self.__reverse_keys.get(msg[0], -1)\n        last = self.__reverse_keys.get(msg[-1], -1)\n        \n        # 校验\n        if 0 <= first <= 109 and 0 <= last <= 109 and not (first + last - 109):\n            type = msg[-2]\n            msg_id, id = map(self.__base2dec, msg[:-2].split('.'))\n            return msg_id, type, id\n        return None\n        \n    def __combine_piece(self, uid, msg):\n        # None/''\n        if not msg:\n            return None\n        if uid not in self.__read:\n            self.__read[uid] = {}\n        user_danmus = self.__read[uid]\n        msg_id, type, id = msg\n        msg_id_wanted = (msg_id - 1) if (msg_id % 2) else (msg_id + 1)\n        id_wanted = user_danmus.pop(msg_id_wanted, None)\n        if id_wanted is not None:\n            if msg_id % 2:\n                return type, id_wanted, id\n            else:\n                return type, id, id_wanted\n        else:\n            user_danmus[msg_id] = id\n            return None\n        \n    def handle_danmu(self, body):\n        dic = json.loads(body.decode('utf-8'))\n        cmd = dic['cmd']\n        # print(cmd)\n        if cmd == 'DANMU_MSG':\n            info = dic['info']\n            ori = info[1]\n            uid = info[2][0]\n            # print(ori)\n            try:\n                msg = self.__reverse(ori)\n                '''\n                if msg is not None:\n                    msg_id, type, id = msg\n                    if type == '~' and not msg_id % 2:\n                        storm_id = id\n                        print('节奏风暴', storm_id)\n                        rafflehandler.Rafflehandler.Put2Queue((storm_id,), rafflehandler.handle_1_storm_raffle)\n                '''        \n                \n                result = self.__combine_piece(uid, msg)\n                # print('监控read dic', self.__read)\n                if result is None:\n                    return True\n                # print(result)\n                type, raffle_id, room_id = result\n                if type == '+':\n                    printer.info([f'{self._area_id}号弹幕监控检测到{room_id:^9}的大航海(id: {raffle_id})'], True)\n                    rafflehandler.Rafflehandler.Put2Queue((room_id, raffle_id), rafflehandler.handle_1_room_guard)\n                    Statistics.add2pushed_raffle('Yj协同大航海', 2)\n            except Exception:\n                printer.warn(f'Yj监控房间内可能有恶意干扰{uid}: {ori}')\n        return True\n                    \n                    \n               \n    \n"
  },
  {
    "path": "online_net.py",
    "content": "from bilibili import bilibili\nfrom configloader import ConfigLoader\nimport rsa\nimport base64\nfrom urllib import parse\nimport printer\nimport asyncio\n\n    \ndef calc_name_passw(key, Hash, username, password):\n    pubkey = rsa.PublicKey.load_pkcs1_openssl_pem(key.encode())\n    password = base64.b64encode(rsa.encrypt((Hash + password).encode('utf-8'), pubkey))\n    password = parse.quote_plus(password)\n    username = parse.quote_plus(username)\n    return username, password\n\n\ndef LoginWithPwd():\n    username = ConfigLoader().dic_bilibili['account']['username']\n    password = ConfigLoader().dic_bilibili['account']['password']\n    response = bilibili.request_getkey()\n    value = response.json()['data']\n    key = value['key']\n    Hash = str(value['hash'])\n    username, password = calc_name_passw(key, Hash, username, password)\n    captcha = None\n    response = bilibili.normal_login(username, password, captcha)\n    while response.json()['code'] == -105:\n        captcha = bilibili.get_captcha(username, password)\n        response = bilibili.normal_login(username, password, captcha)\n    json_rsp = response.json()\n    # print(json_rsp)\n    if not json_rsp['code'] and not json_rsp['data']['status']:\n        data = json_rsp['data']\n        access_key = data['token_info']['access_token']\n        refresh_token = data['token_info']['refresh_token']\n        cookie = data['cookie_info']['cookies']\n        generator_cookie = (f'{i[\"name\"]}={i[\"value\"]}' for i in cookie)\n        cookie_format = ';'.join(generator_cookie)\n        dic_saved_session = {\n            'csrf': cookie[0]['value'],\n            'access_key': access_key,\n            'refresh_token': refresh_token,\n            'cookie': cookie_format,\n            'uid': cookie[1]['value']\n            }\n        # print(dic_saved_session)\n        bilibili.load_session(dic_saved_session)\n        if ConfigLoader().dic_user['other_control']['keep-login']:\n            ConfigLoader().write2bilibili(dic_saved_session)\n        printer.info(['登陆成功'], True)\n        return True\n        \n    else:\n        printer.info([f'登录失败,错误信息为:{json_rsp}'], True)\n        return False\n\n\ndef login():\n    if ConfigLoader().dic_bilibili['saved-session']['cookie']:\n        bilibili.load_session(ConfigLoader().dic_bilibili['saved-session'])\n        return HandleExpire()\n    else:\n        return LoginWithPwd()\n            \n\ndef logout():\n    response = bilibili.request_logout()\n    if response.json()['code']:\n        print('登出失败', response)\n    else:\n        print('成功退出登陆')\n\n                \ndef check_token():\n    response = bilibili.request_check_token()\n    json_response = response.json()\n    if not json_response['code'] and 'mid' in json_response['data']:\n        print('token有效期检查: 仍有效')\n        # print(json_response)\n        return True\n    print('token可能过期', json_response)\n    return False\n\n        \ndef RefreshToken():\n    # return\n    response = bilibili.request_refresh_token()\n    json_response = response.json()\n    # print(json_response)\n    \n    if not json_response['code'] and 'mid' in json_response['data']['token_info']:\n        print('token刷新成功')\n        data = json_response['data']\n        access_key = data['token_info']['access_token']\n        refresh_token = data['token_info']['refresh_token']\n        cookie = data['cookie_info']['cookies']\n        generator_cookie = (f'{i[\"name\"]}={i[\"value\"]}' for i in cookie)\n        cookie_format = ';'.join(generator_cookie)\n        dic_saved_session = {\n            'csrf': cookie[0]['value'],\n            'access_key': access_key,\n            'refresh_token': refresh_token,\n            'cookie': cookie_format\n            }\n        bilibili.load_session(dic_saved_session)\n        if ConfigLoader().dic_user['other_control']['keep-login']:\n            ConfigLoader().write2bilibili(dic_saved_session)\n        # 更新token信息\n        return True\n    print('联系作者(token刷新失败，cookie过期)', json_response)\n    return False\n\n        \ndef HandleExpire():\n    if not check_token():\n        if not RefreshToken():\n            return LoginWithPwd()\n        else:\n            if not check_token():\n                print('请联系作者!!!!!!!!!')\n                return LoginWithPwd()\n    return True\n    \n            \nclass OnlineNet():\n    instance = None\n\n    def __new__(cls, *args, **kw):\n        if not cls.instance:\n            cls.instance = super(OnlineNet, cls).__new__(cls, *args, **kw)\n            cls.instance.bili = bilibili()\n            cls.instance.var_is_online = True\n            cls.instance.list_delay = []\n        return cls.instance\n     \n    @property\n    def is_online(self):\n        return self.var_is_online\n        \n    @is_online.setter\n    def is_online(self, setting):\n        self.var_is_online = setting\n        if setting:\n            for future in self.list_delay:\n                future.set_result(True)\n            del self.list_delay[:]\n            \n    async def req(self, str_func, *args):\n        while True:\n            rsp = await getattr(self.bili, str_func)(*args)\n            is_online = self.is_online\n            # print(rsp)\n            if not is_online:\n                future = asyncio.Future()\n                self.list_delay.append(future)\n                await future\n            # 未登陆且未处理\n            if rsp == 3 and is_online:\n                printer.info([f'判定出现了登陆失败，且未处理'], True)\n                self.is_online = False\n                # login\n                HandleExpire()\n                # await asyncio.sleep(10)\n                print(self.list_delay)\n                printer.info([f'已经登陆了'], True)\n                self.is_online = True\n                # rsp = await getattr(self.bili, str_func)(*args)\n            # 未登陆，但已处理\n            elif not is_online:\n                printer.info([f'判定出现了登陆失败，已经处理'], True)\n                # rsp = await getattr(self.bili, str_func)(*args)\n            else:\n                return rsp\n"
  },
  {
    "path": "printer.py",
    "content": "import sys\nimport time\nfrom configloader import ConfigLoader\nif sys.platform == 'ios':\n    import console\n\n        \nclass BasePrinter():\n    def init_config(self):\n        configs = ConfigLoader()\n        self.dic_color = configs.dic_color\n        self.dic_user = configs.dic_user\n        self.dic_title = configs.dic_title\n        self.danmu_control = self.dic_user['print_control']['danmu']\n        \n    def control_printer(self, danmu_control=None, debug_control=None):\n        if danmu_control is not None:\n            self.danmu_control = danmu_control\n            ConfigLoader().dic_user['print_control']['danmu'] = danmu_control\n        if debug_control is not None:\n            ConfigLoader().dic_user['print_control']['debug'] = debug_control\n            self.debug_control = debug_control\n            \n    def timestamp(self):\n        str_time = time.strftime(\"[%Y-%m-%d %H:%M:%S] \", time.localtime())\n        return str_time\n        \n    def info(self, list_msg, tag_time=False):\n        if tag_time:\n            print(self.timestamp(), end='')\n        for msg in list_msg:\n            print(msg)\n            \n    def warn(self, msg):\n        print(msg, file=sys.stderr)\n        with open('bili.log', 'a', encoding='utf-8') as f:\n            f.write(f'{self.timestamp()}{msg}\\n')\n        \n    def debug(self, msg):\n        if ConfigLoader().dic_user['print_control']['debug']:\n            self.warn(msg)\n            \n    def error(self, msg):\n        self.warn(msg)\n        sys.exit(-1)\n    \n    \nclass PythonistaPrinter(BasePrinter):\n            \n    # \"#969696\"\n    def hex_to_rgb_percent(self, hex_str):\n        return tuple(int(n, 16)/255 for n in (hex_str[1:3], hex_str[3:5], hex_str[5:7]))\n        \n    # 弹幕 礼物 。。。。type\n    def print_danmu(self, dic_msg, type='normal'):\n        if not self.danmu_control:\n            return\n        info = dic_msg['info']\n\n        list_msg = []\n        list_color = []\n        if info[7] == 3:\n            # print('舰', end=' ')\n            list_msg.append('⚓️ ')\n            list_color.append([])\n        else:\n            if info[2][3] == 1:\n                if info[2][4] == 0:\n                    list_msg.append('爷 ')\n                    list_color.append(self.dic_color['others']['vip'])\n                else:\n                    list_msg.append('爷 ')\n                    list_color.append(self.dic_color['others']['svip'])\n            if info[2][2] == 1:\n                list_msg.append('房管 ')\n                list_color.append(self.dic_color['others']['admin'])\n                \n            # 勋章\n            if info[3]:\n                list_color.append(self.dic_color['fans-level'][f'fl{info[3][0]}'])\n                list_msg.append(f'{info[3][1]}|{info[3][0]} ')\n            # 等级\n            if not info[5]:\n                list_color.append(self.dic_color['user-level'][f'ul{info[4][0]}'])\n                list_msg.append(f'UL{info[4][0]} ')\n        try:\n            if info[2][7]:\n                list_color.append(self.hex_to_rgb_percent(info[2][7]))\n                list_msg.append(info[2][1] + ':')\n            else:\n                list_msg.append(info[2][1] + ':')\n                list_color.append(self.dic_color['others']['default_name'])\n        except:\n            print(\"# 小电视降临本直播间\")\n            list_msg.append(info[2][1] + ':')\n            list_color.append(self.dic_color['others']['default_name'])\n            \n        list_msg.append(info[1])\n        list_color.append([])\n        for i, j in zip(list_msg, list_color):\n            console.set_color(*j)\n            print(i, end='')\n        print()\n        console.set_color()\n\n                \nclass NormalPrinter(BasePrinter):\n        \n    def print_danmu(self, dic_msg, type='normal'):\n        if not self.danmu_control:\n            return\n        info = dic_msg['info']\n\n        list_msg = []\n        if info[7] == 3:\n            # print('舰', end=' ')\n            list_msg.append('⚓️ ')\n        else:\n            if info[2][3] == 1:\n                if info[2][4] == 0:\n                    list_msg.append('爷 ')\n                else:\n                    list_msg.append('爷 ')\n            if info[2][2] == 1:\n                list_msg.append('房管 ')\n                \n            # 勋章\n            if info[3]:\n                list_msg.append(f'{info[3][1]}|{info[3][0]} ')\n            # 等级\n            if not info[5]:\n                list_msg.append(f'UL{info[4][0]} ')\n        try:\n            if info[2][7]:\n                list_msg.append(info[2][1] + ':')\n            else:\n                list_msg.append(info[2][1] + ':')\n        except:\n            print(\"# 小电视降临本直播间\")\n            list_msg.append(info[2][1] + ':')\n            \n        list_msg.append(info[1])\n        print(''.join(list_msg))\n \nif (sys.platform == 'ios'):\n    printer = PythonistaPrinter()\nelse:\n    printer = NormalPrinter()\n\n\ndef init_config():\n    printer.init_config()\n\n\ndef info(list_msg, tag_time=False):\n    printer.info(list_msg, tag_time)\n\n\ndef warn(msg):\n    printer.warn(msg)\n        \n        \ndef error(msg):\n    printer.error(msg)\n   \n             \ndef debug(msg):\n    printer.debug(msg)\n  \n      \ndef print_danmu(dic_msg, type='normal'):\n    printer.print_danmu(dic_msg, type)\n    \n    \ndef control_printer(danmu_control=None, debug_control=None):\n    printer.control_printer(danmu_control, debug_control)\n            \n"
  },
  {
    "path": "rafflehandler.py",
    "content": "from online_net import OnlineNet\nfrom statistics import Statistics\nimport printer\nimport utils\nimport asyncio\nimport time\nimport random\nfrom bilitimer import BiliTimer\n\n\ndef CurrentTime():\n    currenttime = int(time.time())\n    return currenttime\n\n\nclass Rafflehandler:\n    __slots__ = ('queue_raffle', 'list_raffle_id')\n    instance = None\n\n    def __new__(cls, *args, **kw):\n        if not cls.instance:\n            cls.instance = super(Rafflehandler, cls).__new__(cls, *args, **kw)\n            cls.instance.queue_raffle = asyncio.Queue()\n            cls.instance.list_raffle_id = []\n        return cls.instance\n        \n    async def run(self):\n        while True:\n            raffle = await self.queue_raffle.get()\n            await asyncio.sleep(0.5)\n            list_raffle0 = [self.queue_raffle.get_nowait() for i in range(self.queue_raffle.qsize())]\n            list_raffle0.append(raffle)\n            list_raffle = list(set(list_raffle0))\n                \n            # print('过滤完毕')\n            # if len(list_raffle) != len(list_raffle0):\n            # print('过滤机制起作用')\n            \n            tasklist = []\n            for i in list_raffle:\n                i = list(i)\n                i[0] = list(i[0])\n                for j in range(len(i[0])):\n                    if isinstance(i[0][j], tuple):\n                        # print('检测')\n                        # i[0] = list(i[0])\n                        i[0][j] = await i[0][j][1](*(i[0][j][0]))\n                # print(i)\n                task = asyncio.ensure_future(i[1](*i[0]))\n                tasklist.append(task)\n            \n            # await asyncio.wait(tasklist, return_when=asyncio.ALL_COMPLETED)\n            \n    @staticmethod\n    def Put2Queue(value, func):\n        # print('welcome to appending')\n        Rafflehandler.instance.queue_raffle.put_nowait((value, func))\n        # print('appended')\n        return\n        \n    @staticmethod\n    async def Put2Queue_wait(value, func):\n        # print('welcome to appending')\n        await Rafflehandler.instance.queue_raffle.put((value, func))\n        # print('appended')\n        return\n            \n    @staticmethod\n    def getlist():\n        print('目前TV任务队列状况', Rafflehandler.instance.queue_raffle.qsize())\n        \n    def add2raffle_id(self, raffle_id):\n        self.list_raffle_id.append(raffle_id)\n        if len(self.list_raffle_id) > 150:\n            # print(self.list_raffle_id)\n            del self.list_raffle_id[:75]\n            # print(self.list_raffle_id)\n    \n    def check_duplicate(self, raffle_id):\n        return (raffle_id in self.list_raffle_id)\n        \n\nasync def handle_1_TV_raffle(num, real_roomid, raffleid, raffle_type):\n    while True:\n        json_response2 = await OnlineNet().req('get_gift_of_TV_app', real_roomid, raffleid, raffle_type)\n        code = json_response2['code']\n        if not code:\n            break\n        elif code == -403:\n            return True\n        elif code == -405:\n            print('没抢到。。。。。')\n            printer.warn(f'{raffleid}  {raffle_type} {num}')\n            return False\n        elif code == 400:\n            print(json_response2)\n            return\n            tasklist = []\n            for i in range(60):\n                task = asyncio.ensure_future(handle_1_TV_raffle_black(num, real_roomid, raffleid, raffle_type))\n                tasklist.append(task)\n            await asyncio.wait(tasklist, return_when=asyncio.FIRST_COMPLETED)\n            return\n        elif code != -401 and code != -403:\n            pass\n        print('如果循环请联系作者', num, real_roomid, raffleid, raffle_type)\n        \n    data = json_response2['data']\n    Statistics.append_to_TVlist(raffleid, real_roomid)\n    Statistics.add_to_result(data['gift_name'], int(data['gift_num']))\n    printer.info([f'参与了房间{real_roomid:^9}的道具抽奖'], True)\n    # printer.info([f'# 道具抽奖状态: {json_response2[\"msg\"]}'])\n    printer.info([f'# 房间{real_roomid:^9}网页端活动抽奖结果: {data[\"gift_name\"]}X{data[\"gift_num\"]}'])\n    return True\n \n    \nasync def handle_1_guard_raffle(num, roomid, raffleid):\n    await asyncio.sleep(random.uniform(0.5, min(30, num * 1.3)))\n    json_response2 = await OnlineNet().req('get_gift_of_guard', roomid, raffleid)\n    # print(json_response2)\n    if not json_response2['code']:\n        print(\"# 获取到房间 %s 的提督/舰长奖励: \" % (roomid), json_response2['data']['message'])\n        # print(json_response2)\n        Statistics.append_to_guardlist()\n    else:\n        print(json_response2)\n    return True\n    \nasync def handle_1_storm_raffle(id):\n    json_response1 = await OnlineNet().req('get_gift_of_storm', id)\n    print(json_response1)\n \n                                       \nasync def handle_1_activity_raffle(num, text1, raffleid):\n    # print('参与')\n    # await asyncio.sleep(random.uniform(0.5, min(30, num * 1.3)))\n    json_response1 = await OnlineNet().req('get_gift_of_events_app', text1, raffleid)\n    # json_pc_response = await OnlineNet().req('get_gift_of_events_web', text1, text2, raffleid)\n    # print(json_response1)\n    printer.info([f'参与了房间{text1:^9}的活动抽奖'], True)\n\n    if not json_response1['code']:\n        printer.info([f'# 移动端活动抽奖结果: {json_response1[\"data\"][\"gift_desc\"]}'])\n        Statistics.add_to_result(*(json_response1['data']['gift_desc'].split('X')))\n    elif json_response1['code'] == 400:\n        print(json_response1)\n        return\n        tasklist = []\n        for i in range(60):\n            task = asyncio.ensure_future(handle_1_activity_raffle_black(num, text1, raffleid))\n            tasklist.append(task)\n        await asyncio.wait(tasklist, return_when=asyncio.FIRST_COMPLETED)\n        return\n        # print(json_response1)\n    else:\n        printer.info([f'# 移动端活动抽奖结果: {json_response1}'])\n        \n    # printer.info(\n    # [f'# 网页端活动抽奖状态:  {json_pc_response}'])\n    # if not json_pc_response['code']:\n    #    Statistics.append_to_activitylist(raffleid, text1)\n    # else:\n    #    print(json_pc_response)\n    return True\n\n                \nasync def handle_1_room_TV(real_roomid):\n    result = await utils.enter_room(real_roomid)\n    if result:\n        json_response = await OnlineNet().req('get_giftlist_of_TV', real_roomid)\n        current_time = CurrentTime()\n        # print(json_response['data']['list'])\n        checklen = json_response['data']['list']\n        list_available_raffleid = []\n        for j in checklen:\n            raffle_id = j['raffleId']\n            raffle_type = j['type']\n            time_wanted = j['time_wait'] + current_time\n            # 处理一些重复\n            if not Rafflehandler().check_duplicate(raffle_id):\n                print(raffle_id)\n                list_available_raffleid.append((raffle_id, raffle_type, time_wanted))\n                Rafflehandler().add2raffle_id(raffle_id)\n            \n        num_available = len(list_available_raffleid)\n        # print(list_available_raffleid)\n        for raffle_id, raffle_type, time_wanted in list_available_raffleid:\n            BiliTimer.append2list_jobs(handle_1_TV_raffle, time_wanted, (num_available, real_roomid, raffle_id, raffle_type))\n            \nasync def handle_1_room_storm(roomid):\n    result = await utils.enter_room(roomid)\n    if result:\n        temp = await OnlineNet().req('get_giftlist_of_storm', roomid)\n        check = len(temp['data'])\n        list_available_raffleid = []\n        if check != 0 and temp['data']['hasJoin'] != 1:\n            id = temp['data']['id']\n            list_available_raffleid.append((id, 0))\n        for id, time_wanted in list_available_raffleid:\n            BiliTimer.append2list_jobs(handle_1_storm_raffle, time_wanted, (id,))\n\nasync def handle_1_room_activity(text1):\n    result = await utils.enter_room(text1)\n    if result:\n        json_response = await OnlineNet().req('get_giftlist_of_events', text1)\n        # print(json_response)\n        checklen = json_response['data']['lotteryInfo']\n        list_available_raffleid = []\n        for j in checklen:\n            # await asyncio.sleep(random.uniform(0.5, 1))\n            # resttime = j['time']\n            raffleid = j['eventType']\n            # if Statistics.check_activitylist(text1, raffleid):\n            list_available_raffleid.append(raffleid)\n        tasklist = []\n        num_available = len(list_available_raffleid)\n        # print(list_available_raffleid)\n        for raffleid in list_available_raffleid:\n            task = asyncio.ensure_future(handle_1_activity_raffle(num_available, text1, raffleid))\n            tasklist.append(task)\n        if tasklist:\n            raffle_results = await asyncio.gather(*tasklist)\n            if False in raffle_results:\n                print('有繁忙提示，稍后重新尝试')\n                Rafflehandler.Put2Queue((text1), handle_1_room_activity)\n\n                \nasync def handle_1_room_guard(roomid, raffleid=None):\n    result = await utils.enter_room(roomid)\n    if result:\n        if raffleid is not None:\n            json_response1 = {'data': [{'id': raffleid}]}\n        else:\n            for i in range(10):\n                json_response1 = await OnlineNet().req('get_giftlist_of_guard', roomid)\n                # print(json_response1)\n                if not json_response1['data']:\n                    await asyncio.sleep(1)\n                else:\n                    break\n            if not json_response1['data']:\n                print(f'{roomid}没有guard或者guard已经领取')\n                return\n        list_available_raffleid = []\n        # guard这里领取后，list对应会消失，其实就没有status了，这里是为了统一\n        for j in json_response1['data']:\n            raffle_id = j['id']\n            if not Rafflehandler().check_duplicate(raffle_id):\n                # print(raffle_id)\n                list_available_raffleid.append(raffle_id)\n                Rafflehandler().add2raffle_id(raffle_id)\n                        \n        tasklist = []\n        num_available = len(list_available_raffleid)\n        for raffleid in list_available_raffleid:\n            task = asyncio.ensure_future(handle_1_guard_raffle(num_available, roomid, raffleid))\n            tasklist.append(task)\n        if tasklist:\n            raffle_results = await asyncio.gather(*tasklist)\n            if False in raffle_results:\n                print('有繁忙提示，稍后重新尝试')\n                Rafflehandler.Put2Queue((roomid,), handle_1_room_guard)\n                \n         \nasync def handle_1_TV_raffle_black(num, real_roomid, raffleid, raffle_type):\n    # print('ffffffffffggggdgdfddf')\n    for i in range(50):\n        json_response2 = await OnlineNet().req('get_gift_of_TV_app', real_roomid, raffleid, raffle_type)\n        code = json_response2['code']\n        if not code:\n            break\n        elif code == -403:\n            return True\n        elif code == -405:\n            print('没抢到。。。。。')\n            printer.warn(raffleid)\n            return False\n        elif code != -401 and code != -403:\n            # print('00', json_response2)\n            pass\n        # await asyncio.sleep()\n    code = json_response2['code']\n    if code:\n        await asyncio.sleep(5)\n        return\n    data = json_response2['data']\n    Statistics.append_to_TVlist(raffleid, real_roomid)\n    Statistics.add_to_result(data['gift_name'], int(data['gift_num']))\n    printer.info([f'参与了房间{real_roomid:^9}的道具抽奖'], True)\n    # printer.info([f'# 道具抽奖状态: {json_response2[\"msg\"]}'])\n    printer.info([f'# 房间{real_roomid:^9}网页端活动抽奖结果: {data[\"gift_name\"]}X{data[\"gift_num\"]}'])\n    return True\n    \nasync def handle_1_activity_raffle_black(num, text1, raffleid):\n    # print('参与')\n    # await asyncio.sleep(random.uniform(0.5, min(30, num * 1.3)))\n    for i in range(50):\n        json_response1 = await OnlineNet().req('get_gift_of_events_app', text1, raffleid)\n        code = json_response1['code']\n        if not code:\n            break\n        elif code == -403:\n            return True\n        elif code == -405:\n            print('没抢到。。。。。')\n            printer.warn(raffleid)\n            return False\n        elif code != -401 and code != -403:\n            # print('00', json_response2)\n            pass\n    # json_pc_response = await OnlineNet().req('get_gift_of_events_web', text1, text2, raffleid)\n    # print(json_response1)\n    printer.info([f'参与了房间{text1:^9}的活动抽奖'], True)\n\n    if not json_response1['code']:\n        printer.info([f'# 移动端活动抽奖结果: {json_response1[\"data\"][\"gift_desc\"]}'])\n        Statistics.add_to_result(*(json_response1['data']['gift_desc'].split('X')))\n    else:\n        # print(json_response1)\n        printer.info([f'# 移动端活动抽奖结果: {json_response1}'])\n\n    return True\n"
  },
  {
    "path": "requirements.txt",
    "content": "requests\nrsa\naiohttp\n# Pillow 当你需要自己输入验证码的时候请安装\ntoml\n"
  },
  {
    "path": "run.py",
    "content": "import OnlineHeart\nimport Silver\nimport Tasks\nimport connect\nfrom rafflehandler import Rafflehandler\nimport asyncio\nimport printer\nfrom statistics import Statistics\nfrom bilibili import bilibili\nfrom configloader import ConfigLoader\nimport threading\nimport os\nimport online_net\nimport bili_console\nfrom bilitimer import BiliTimer\n\n\nloop = asyncio.get_event_loop()\nfileDir = os.path.dirname(os.path.realpath(__file__))\n\nconf = ConfigLoader(fileDir)\narea_ids = conf.dic_user['other_control']['area_ids']\n\n# print('Hello world.')\nprinter.init_config()\nbilibili()\nonline_net.login()\nonline_net.OnlineNet()\nStatistics(len(area_ids))\n\nrafflehandler = Rafflehandler()\nvar_console = bili_console.Biliconsole(loop)\n\nlist_raffle_connection = [connect.RaffleConnect(i) for i in area_ids]\nlist_raffle_connection_task = [i.run() for i in list_raffle_connection]\nyjconnection = connect.YjConnection()\n\ndanmu_connection = connect.connect()\n\n\nbili_timer = BiliTimer(loop)\n\nconsole_thread = threading.Thread(target=var_console.cmdloop)\n\nconsole_thread.start()\n\nTasks.init()\ntasks = [\n    OnlineHeart.run(),\n    Silver.run(),\n    danmu_connection.run(),\n    rafflehandler.run(),\n    yjconnection.run()\n]\ntry:\n    loop.run_until_complete(asyncio.wait(tasks + list_raffle_connection_task))\nexcept KeyboardInterrupt:\n    # print(sys.exc_info()[0], sys.exc_info()[1])\n    if ConfigLoader().dic_user['other_control']['keep-login']:\n        pass\n    else:\n        response = online_net.logout()\n    \nconsole_thread.join()\n\nloop.close()\n    \n\n\n"
  },
  {
    "path": "statistics.py",
    "content": "class Statistics:\n    instance = None\n\n    def __new__(cls, area_num=0):\n        if not cls.instance:\n            cls.instance = super(Statistics, cls).__new__(cls)\n            cls.instance.area_num = area_num\n            cls.instance.activity_id_list = []\n            # cls.instance.activity_time_list = []\n            cls.instance.TV_id_list = []\n            # cls.instance.TV_time_list = []\n            cls.instance.pushed_raffle = {}\n            \n            cls.instance.joined_raffle = {}\n            cls.instance.result = {}\n            # cls.instance.TVsleeptime = 185\n            # cls.instance.activitysleeptime = 125\n        return cls.instance\n\n    @staticmethod\n    def add_to_result(type, num):\n        inst = Statistics.instance\n        inst.result[type] = inst.result.get(type, 0) + int(num)\n\n    @staticmethod\n    def getlist():\n        inst = Statistics.instance\n        print('本次推送抽奖统计：')\n        for k, v in inst.pushed_raffle.items():\n            if isinstance(v, int):\n                print(f'{v:^5} X {k}')\n            else:\n                print(f'{v:^5.2f} X {k}')\n            \n        print()\n        print('本次参与抽奖统计：')\n        for k, v in inst.joined_raffle.items():\n            print(f'{v:^5} X {k}')\n\n        print()\n        print('本次抽奖结果统计：')\n        for k, v in inst.result.items():\n            print(f'{v:^5} X {k}')\n\n    @staticmethod\n    def append_to_activitylist(raffleid, text1, time=''):\n        inst = Statistics.instance\n        inst.activity_id_list.append((text1, raffleid))\n        # inst.activity_time_list.append(int(time))\n        # inst.activity_time_list.append(int(CurrentTime()))\n        inst.append2joined_raffle('活动(合计)')\n        # print(\"activity加入成功\", inst.joined_event)\n\n    @staticmethod\n    def append_to_TVlist(raffleid, real_roomid, time=''):\n        inst = Statistics.instance\n        inst.TV_id_list.append((real_roomid, raffleid))\n        # inst.TV_time_list.append(int(time)+int(CurrentTime()))\n        # inst.TV_time_list.append(int(CurrentTime()))\n        inst.append2joined_raffle('小电视(合计)')\n        # print(\"tv加入成功\", inst.joined_TV)\n        \n    @staticmethod\n    def append_to_guardlist():\n        inst = Statistics.instance\n        inst.append2joined_raffle('大航海(合计)')\n        \n    @staticmethod\n    def append2joined_raffle(type, num=1):\n        inst = Statistics.instance\n        inst.joined_raffle[type] = inst.joined_raffle.get(type, 0) + int(num)\n     \n    @staticmethod\n    def add2pushed_raffle(raffle_name, broadcast_type=0, num=1):\n        # broadcast_type 0全区 1分区 2本房间\n        inst = Statistics.instance\n        if broadcast_type == 0:\n            inst.pushed_raffle[raffle_name] = inst.pushed_raffle.get(raffle_name, 0) + int(num) / inst.area_num\n        else:\n            inst.pushed_raffle[raffle_name] = inst.pushed_raffle.get(raffle_name, 0) + int(num)\n                    \n    @staticmethod\n    def check_TVlist(real_roomid, raffleid):\n        inst = Statistics.instance\n        if (real_roomid, raffleid) not in inst.TV_id_list:\n            return True\n        return False\n\n    @staticmethod\n    def check_activitylist(real_roomid, raffleid):\n        inst = Statistics.instance\n        if (real_roomid, raffleid) not in inst.activity_id_list:\n            return True\n        return False\n        \n    @staticmethod\n    def checklist():\n        print('目前activity任务队列状况:', Statistics.instance.activity_id_list)\n        print('TV:', Statistics.instance.TV_id_list)\n"
  },
  {
    "path": "ugly_auto_reboot.py",
    "content": "import subprocess\nimport time\nimport sys\n\nTIME = 3600\nCMD = \"run.py\"\n\n\nclass Auto_Run():\n    def __init__(self, sleep_time, cmd):\n        self.sleep_time = sleep_time\n        self.cmd = cmd\n        self.ext = (cmd[-3:]).lower()\n        self.p = None\n        self.run()\n\n        try:\n            while 1:\n                time.sleep(sleep_time * 20)\n                self.poll = self.p.poll()\n                if self.p.poll() is None:\n                    print(\"restarting......\")\n                    self.p.kill()\n                    self.run()\n\n                else:\n                    print(\"starting......\")\n                    self.run()\n        except KeyboardInterrupt as e:\n            print(\"exit???\")\n\n    def run(self):\n        if self.ext == \".py\":\n            print('start OK!')\n            self.p = subprocess.Popen(['python', '%s' % self.cmd], stdin=sys.stdin, stdout=sys.stdout,\n                                      stderr=sys.stderr, shell=False)\n        else:\n            pass\n\n\napp = Auto_Run(TIME, CMD)\n"
  },
  {
    "path": "utils.py",
    "content": "from online_net import OnlineNet\nimport printer\nimport time\nimport datetime\ntry:\n    from PIL import Image\nexcept ImportError:\n    Image = None\nfrom io import BytesIO\nimport webbrowser\nimport re\nfrom operator import itemgetter\nfrom configloader import ConfigLoader\n\n\ndef adjust_for_chinese(str):\n    SPACE = '\\N{IDEOGRAPHIC SPACE}'\n    EXCLA = '\\N{FULLWIDTH EXCLAMATION MARK}'\n    TILDE = '\\N{FULLWIDTH TILDE}'\n\n    # strings of ASCII and full-width characters (same order)\n    west = ''.join(chr(i) for i in range(ord(' '), ord('~')))\n    east = SPACE + ''.join(chr(i) for i in range(ord(EXCLA), ord(TILDE)))\n\n    # build the translation table\n    full = str.maketrans(west, east)\n    str = str.translate(full).rstrip().split('\\n')\n    md = f'{str[0]:^10}'\n    return md.translate(full)\n\n\ndef CurrentTime():\n    currenttime = int(time.time())\n    return str(currenttime)\n\n\ndef seconds_until_tomorrow():\n    today = datetime.date.today()\n    tomorrow = today + datetime.timedelta(days=1)\n    tomorrow_start_time = int(time.mktime(time.strptime(str(tomorrow), '%Y-%m-%d')))\n    current_time = int(time.mktime(datetime.datetime.now().timetuple()))\n    return tomorrow_start_time - current_time\n\n\nasync def WearingMedalInfo():\n    json_response = await OnlineNet().req('ReqWearingMedal')\n    # print(json_response)\n    if not json_response['code']:\n        data = json_response['data']\n        if data:\n            # print(data['roominfo']['room_id'], data['today_feed'], data['day_limit'])\n            return [(data['roominfo']['room_id'], int(data['day_limit']) - int(data['today_feed']), data['medal_name']), ]\n        else:\n            # print('暂无佩戴任何勋章')\n            return []\n\n        # web api返回值信息少\n\n\nasync def TitleInfo():\n    json_response = await OnlineNet().req('ReqTitleInfo')\n    dic_title = ConfigLoader().dic_title\n    # print(json_response)\n    if not json_response['code']:\n        data = json_response['data']\n        for i in data['list']:\n            if i['level']:\n                max = i['level'][1]\n            else:\n                max = '-'\n            print(dic_title[i['title_pic']['id']], i['activity'], i['score'], max)\n\n\nasync def fetch_medal(show=True, list_wanted_medal=None):\n    printlist = []\n    list_medal = []\n    if show:\n        printlist.append('查询勋章信息')\n        printlist.append(\n            '{} {} {:^12} {:^10} {} {:^6} {}'.format(adjust_for_chinese('勋章'), adjust_for_chinese('主播昵称'), '亲密度', '今日的亲密度', adjust_for_chinese('排名'), '勋章状态', '房间号码'))\n    dic_worn = {'1': '正在佩戴', '0': '待机状态'}\n    json_response = await OnlineNet().req('request_fetchmedal')\n    # print(json_response)\n    if not json_response['code']:\n        for i in json_response['data']['fansMedalList']:\n            if 'roomid' in i:\n                list_medal.append((i['roomid'], int(i['dayLimit']) - int(i['todayFeed']), i['medal_name'], i['level']))\n                if show:\n                    printlist.append('{} {} {:^14} {:^14} {} {:^6} {:^9}'.format(adjust_for_chinese(i['medal_name'] + '|' + str(i['level'])), adjust_for_chinese(i['anchorInfo']['uname']), str(i['intimacy']) + '/' + str(i['next_intimacy']), str(i['todayFeed']) + '/' + str(i['dayLimit']), adjust_for_chinese(str(i['rank'])), dic_worn[str(i['status'])], i['roomid']))\n        if show:\n            printer.info(printlist, True)\n        if list_wanted_medal is not None:\n            list_return_medal = []\n            for roomid in list_wanted_medal:\n                for i in list_medal:\n                    if i[0] == roomid:\n                        list_return_medal.append(i[:3])\n                        break\n        else:\n            list_return_medal = [i[:3] for i in sorted(list_medal, key=itemgetter(3), reverse=True)]\n        return list_return_medal\n\n\nasync def send_danmu_msg_web(msg, roomId):\n    json_response = await OnlineNet().req('request_send_danmu_msg_web', msg, roomId)\n    print(json_response)\n\n\nasync def find_live_user_roomid(wanted_name):\n    print(wanted_name)\n    \n    def check_name_piece(json_rsp, wanted_name):\n        results = json_rsp['result']\n        if results is None:\n            # print('屏蔽全名')\n            return None\n        for i in results:\n            real_name = re.sub(r'<[^>]*>', '', i['uname'])\n            # print('去除干扰', real_name)\n            if real_name == wanted_name:\n                print('找到结果', i)\n                return i\n        return None\n                \n    for i in range(len(wanted_name), 0, -1):\n        name_piece = wanted_name[:i]\n        json_rsp = await OnlineNet().req('request_search_biliuser', name_piece)\n        answer = check_name_piece(json_rsp, wanted_name)\n        if answer is not None:\n            return answer['room_id']\n        # print('结束一次')\n\n    print('第2备份启用')\n    for i in range(len(wanted_name)):\n        name_piece = wanted_name[i:]\n        json_rsp = await OnlineNet().req('request_search_biliuser', name_piece)\n        answer = check_name_piece(json_rsp, wanted_name)\n        if answer is not None:\n            return answer['room_id']\n\n    print('第3备份启用')\n    for i in range(len(wanted_name), 0, -1):\n        name_piece = wanted_name[:i]\n        json_rsp = await OnlineNet().req('request_search_liveuser', name_piece)\n        answer = check_name_piece(json_rsp, wanted_name)\n        if answer is not None:\n            return answer['roomid']\n\n    print('第4备份启用')\n    for i in range(len(wanted_name)):\n        name_piece = wanted_name[i:]\n        json_rsp = await OnlineNet().req('request_search_liveuser', name_piece)\n        answer = check_name_piece(json_rsp, wanted_name)\n        if answer is not None:\n            return answer['roomid']\n\n\nasync def fetch_capsule_info():\n    json_response = await OnlineNet().req('request_fetch_capsule')\n    # print(json_response)\n    if not json_response['code']:\n        data = json_response['data']\n        if data['colorful']['status']:\n            print(f'梦幻扭蛋币: {data[\"colorful\"][\"coin\"]}个')\n        else:\n            print('梦幻扭蛋币暂不可用')\n\n        data = json_response['data']\n        if data['normal']['status']:\n            print(f'普通扭蛋币: {data[\"normal\"][\"coin\"]}个')\n        else:\n            print('普通扭蛋币暂不可用')\n\n\nasync def open_capsule(count):\n    json_response = await OnlineNet().req('request_open_capsule', count)\n    # print(json_response)\n    if not json_response['code']:\n        # print(json_response['data']['text'])\n        for i in json_response['data']['text']:\n            print(i)\n\n\nasync def watch_living_video(cid):\n    import sound\n    sound.set_honors_silent_switch(False)\n    sound.set_volume(1)\n    sound.play_effect('piano:D3')\n    json_response = await OnlineNet().req('request_playurl', cid)\n    print(json_response)\n    if not json_response['code']:\n        data = json_response['data']\n        print(data)\n        webbrowser.open(data)\n\n\nasync def fetch_user_info():\n    json_response = await OnlineNet().req('request_fetch_user_info')\n    json_response_ios = await OnlineNet().req('request_fetch_user_infor_ios')\n    print('[{}] 查询用户信息'.format(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))))\n    if not json_response_ios['code']:\n        gold_ios = json_response_ios['data']['gold']\n    # print(json_response_ios)\n    if not json_response['code']:\n        data = json_response['data']\n        # print(data)\n        userInfo = data['userInfo']\n        userCoinIfo = data['userCoinIfo']\n        uname = userInfo['uname']\n        achieve = data['achieves']\n        user_level = userCoinIfo['user_level']\n        silver = userCoinIfo['silver']\n        gold = userCoinIfo['gold']\n        identification = bool(userInfo['identification'])\n        mobile_verify = bool(userInfo['mobile_verify'])\n        user_next_level = userCoinIfo['user_next_level']\n        user_intimacy = userCoinIfo['user_intimacy']\n        user_next_intimacy = userCoinIfo['user_next_intimacy']\n        user_level_rank = userCoinIfo['user_level_rank']\n        billCoin = userCoinIfo['coins']\n        bili_coins = userCoinIfo['bili_coins']\n        print('# 用户名', uname)\n        size = 100, 100\n        response_face = await OnlineNet().req('request_load_img', userInfo['face'])\n        if Image is not None:\n            img = Image.open(BytesIO(await response_face.read()))\n            img.thumbnail(size)\n            try:\n                img.show()\n            except:\n                pass\n        print(f'# 手机认证状况 {mobile_verify} | 实名认证状况 {identification}')\n        print('# 银瓜子', silver)\n        print('# 通用金瓜子', gold)\n        print('# ios可用金瓜子', gold_ios)\n        print('# 硬币数', billCoin)\n        print('# b币数', bili_coins)\n        print('# 成就值', achieve)\n        print('# 等级值', user_level, '———>', user_next_level)\n        print('# 经验值', user_intimacy)\n        print('# 剩余值', user_next_intimacy - user_intimacy)\n        arrow = int(user_intimacy * 30 / user_next_intimacy)\n        line = 30 - arrow\n        percent = user_intimacy / user_next_intimacy * 100.0\n        process_bar = '# [' + '>' * arrow + '-' * line + ']' + '%.2f' % percent + '%'\n        print(process_bar)\n        print('# 等级榜', user_level_rank)\n        \n\nasync def fetch_bag_list(verbose=False, bagid=None, show=True):\n    json_response = await OnlineNet().req('request_fetch_bag_list')\n    gift_list = []\n    # print(json_response)\n    if show:\n        print('[{}] 查询可用礼物'.format(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))))\n    for i in json_response['data']['list']:\n        bag_id = i['bag_id']\n        gift_id = i['gift_id']\n        gift_num = i['gift_num']\n        gift_name = i['gift_name']\n        expireat = i['expire_at']\n        left_time = (expireat - json_response['data']['time'])\n        if not expireat:\n            left_days = '+∞'.center(6)\n            left_time = None\n        else:\n            left_days = round(left_time / 86400, 1)\n        if bagid is not None:\n            if bag_id == int(bagid):\n                return gift_id, gift_num\n        else:\n            if verbose:\n                print(f'# 编号为{bag_id}的{gift_name:^3}X{gift_num:^4} (在{left_days:^6}天后过期)')\n            elif show:\n                print(f'# {gift_name:^3}X{gift_num:^4} (在{left_days:^6}天后过期)')\n\n        gift_list.append([gift_id, gift_num, bag_id, left_time])\n    # print(gift_list)\n    return gift_list\n\n\nasync def check_taskinfo():\n    json_response = await OnlineNet().req('request_check_taskinfo')\n    # print(json_response)\n    if not json_response['code']:\n        data = json_response['data']\n        double_watch_info = data['double_watch_info']\n        box_info = data['box_info']\n        sign_info = data['sign_info']\n        live_time_info = data['live_time_info']\n        print('双端观看直播：')\n        if double_watch_info['status'] == 1:\n            print('# 该任务已完成，但未领取奖励')\n        elif double_watch_info['status'] == 2:\n            print('# 该任务已完成，已经领取奖励')\n        else:\n            print('# 该任务未完成')\n            if double_watch_info['web_watch'] == 1:\n                print('## 网页端观看任务已完成')\n            else:\n                print('## 网页端观看任务未完成')\n\n            if double_watch_info['mobile_watch'] == 1:\n                print('## 移动端观看任务已完成')\n            else:\n                print('## 移动端观看任务未完成')\n\n        print('直播在线宝箱：')\n        if box_info['status'] == 1:\n            print('# 该任务已完成')\n        else:\n            print('# 该任务未完成')\n            print(f'## 一共{box_info[\"max_times\"]}次重置次数，当前为第{box_info[\"freeSilverTimes\"]}次第{box_info[\"type\"]}个礼包(每次3个礼包)')\n\n        print('每日签到：')\n        if sign_info['status'] == 1:\n            print('# 该任务已完成')\n        else:\n            print('# 该任务未完成')\n\n        if sign_info['signDaysList'] == list(range(1, sign_info['curDay'] + 1)):\n            print('# 当前全勤')\n        else:\n            print('# 出现断签')\n\n        print('直播奖励：')\n        if live_time_info['status'] == 1:\n            print('# 已完成')\n        else:\n            print('# 未完成(目前本项目未实现自动完成直播任务)')\n\n\nasync def check_room(roomid):\n    json_response = await OnlineNet().req('request_check_room', roomid)\n    if not json_response['code']:\n        # print(json_response)\n        print('查询结果:')\n        data = json_response['data']\n\n        if not data['short_id']:\n            print('# 此房间无短房号')\n        else:\n            print(f'# 短号为:{data[\"short_id\"]}')\n        print(f'# 真实房间号为:{data[\"room_id\"]}')\n        return data['room_id']\n    # 房间不存在\n    elif json_response['code'] == 60004:\n        print(json_response['msg'])\n\n\nasync def send_gift_web(roomid, num_wanted, bagid, giftid=None):\n    if giftid is None:\n        giftid, num_owned = await fetch_bag_list(False, bagid)\n        num_wanted = min(num_owned, num_wanted)\n    if not num_wanted:\n        return\n    json_response = await OnlineNet().req('request_check_room', roomid)\n    ruid = json_response['data']['uid']\n    biz_id = json_response['data']['room_id']\n    # 200027 不足数目\n    json_response1 = await OnlineNet().req('request_send_gift_web', giftid, num_wanted, bagid, ruid, biz_id)\n    if not json_response1['code']:\n        # print(json_response1['data'])\n        print(f'# 送出礼物: {json_response1[\"data\"][\"gift_name\"]}X{json_response1[\"data\"][\"gift_num\"]}')\n    else:\n        print(\"# 错误\", json_response1['msg'], roomid, num_wanted, bagid, giftid)\n\n\nasync def fetch_liveuser_info(real_roomid):\n    json_response = await OnlineNet().req('request_fetch_liveuser_info', real_roomid)\n    if not json_response['code']:\n        data = json_response['data']\n        # print(data)\n        print(f'# 主播姓名 {data[\"info\"][\"uname\"]}')\n\n        uid = data['level']['uid']  # str\n        json_response_fan = await OnlineNet().req('request_fetch_fan', real_roomid, uid)\n        # print(json_response_fan)\n        data_fan = json_response_fan['data']\n        if not json_response_fan['code'] and data_fan['medal']['status'] == 2:\n            print(f'# 勋章名字: {data_fan[\"list\"][0][\"medal_name\"]}')\n        else:\n            print('# 该主播暂时没有开通勋章')  # print(json_response_fan)\n\n        size = 100, 100\n        response_face = await OnlineNet().req('request_load_img', data['info']['face'])\n        if Image is not None:\n            img = Image.open(BytesIO(await response_face.read()))\n            img.thumbnail(size)\n            try:\n                img.show()\n            except:\n                pass\n\n\nasync def enter_room(roomid):\n    json_response = await OnlineNet().req('request_check_room', roomid)\n\n    if not json_response['code']:\n        data = json_response['data']\n        param1 = data['is_hidden']\n        param2 = data['is_locked']\n        param3 = data['encrypted']\n        if any((param1, param2, param3)):\n            printer.info([f'抽奖脚本检测到房间{roomid:^9}为异常房间'], True)\n            printer.warn(f'抽奖脚本检测到房间{roomid:^9}为异常房间')\n            return False\n        else:\n            await OnlineNet().req('post_watching_history', roomid)\n            return True\n\n\nasync def GiveCoin2Av(video_id, num):\n    if num not in (1, 2):\n        return False\n    # 10004 稿件已经被删除\n    # 34005 超过，满了\n    # -104 不足硬币\n    json_rsp = await OnlineNet().req('ReqGiveCoin2Av', video_id, num)\n    code = json_rsp['code']\n    if not code:\n        print(f'给视频av{video_id}投{num}枚硬币成功')\n        return True\n    else:\n        print('投币失败', json_rsp['message'])\n        if code == -104:\n            return None\n        return False\n\n\nasync def GetTopVideoList():\n    text_rsp = await OnlineNet().req('req_fetch_av')\n    list_av = re.findall(r'(?<=www.bilibili.com/video/av)\\d+(?=/)', text_rsp)\n    list_av = list(set(list_av))\n    return list_av\n\n\nasync def fetch_uper_video(list_mid):\n    list_av = []\n    for mid in list_mid:\n        json_rsp = await OnlineNet().req('req_fetch_uper_video', mid, 1)\n        # print(json_rsp)\n        data = json_rsp['data']\n        pages = data['pages']\n        if data['vlist']:\n            list_av += [av['aid'] for av in data['vlist']]\n        for page in range(2, pages + 1):\n            json_rsp = await OnlineNet().req('req_fetch_uper_video', mid, page)\n            # print(json_rsp)\n            data = json_rsp['data']\n            list_av += [av['aid'] for av in data['vlist']]\n    # print(len(list_av), list_av)\n    return list_av\n\n\nasync def GetVideoCid(video_aid):\n    json_rsp = await OnlineNet().req('ReqVideoCid', video_aid)\n    # print(json_rsp[0]['cid'])\n    return (json_rsp[0]['cid'])\n\n\nasync def GetRewardInfo(show=True):\n    json_rsp = await OnlineNet().req('ReqMasterInfo')\n    data = json_rsp['data']\n    login = data['login']\n    watch_av = data['watch_av']\n    coins_av = data['coins_av']\n    share_av = data['share_av']\n    level_info = data[\"level_info\"]\n    current_exp = level_info['current_exp']\n    next_exp = level_info['next_exp']\n    if next_exp == -1:\n        next_exp = current_exp\n    print(f'# 主站等级值 {level_info[\"current_level\"]}')\n    print(f'# 主站经验值 {level_info[\"current_exp\"]}')\n    print(f'# 主站剩余值 {- current_exp + next_exp}')\n    arrow = int(current_exp * 30 / next_exp)\n    line = 30 - arrow\n    percent = current_exp / next_exp * 100.0\n    process_bar = '# [' + '>' * arrow + '-' * line + ']' + '%.2f' % percent + '%'\n    print(process_bar)\n    if show:\n        print(f'每日登陆：{login} 每日观看：{watch_av} 每日投币经验：{coins_av}/50 每日分享：{share_av}')\n    return login, watch_av, coins_av, share_av\n    \n        \nasync def FetchRoomArea(roomid):\n    json_response = await OnlineNet().req('ReqRoomInfo', roomid)\n\n    if not json_response['code']:\n        # print(json_response)\n        # print(json_response['data']['parent_area_id'])\n        return json_response['data']['parent_area_id']\n    \n    \nasync def check_room_for_danmu(room_id, area_id):\n    json_response = await OnlineNet().req('request_check_room', room_id)\n    data = json_response['data']\n    is_hidden = data['is_hidden']\n    is_locked = data['is_locked']\n    is_encrypted = data['encrypted']\n    if any((is_hidden, is_locked, is_encrypted)):\n        is_normal = False\n    else:\n        is_normal = True\n            \n    json_response = await OnlineNet().req('ReqRoomInfo', room_id)\n    data = json_response['data']\n    is_open = True if data['live_status'] == 1 else False\n    current_area_id = data['parent_area_id']\n    # print(is_hidden, is_locked, is_encrypted, is_open, current_area_id)\n    is_ok = (area_id == current_area_id) and is_normal and is_open\n    return is_ok\n            \n            \n            \n"
  }
]