diff --git a/README.md b/README.md
index fe1befc..1476707 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-
Kook-Valorant--bot
+Kook-Valorant-Bot
这是一个KOOK的「Valorant」小机器人
diff --git a/code/api.py b/code/api.py
index 29e1148..9b2218f 100644
--- a/code/api.py
+++ b/code/api.py
@@ -2,7 +2,7 @@
import traceback
from aiohttp import web
from utils.Gtime import GetTime
-from utils.api.ApiHandler import tfa_code_requeset, afd_request, login_img_request, img_draw_request
+from utils.api import ApiHandler
# 初始化节点
routes = web.RouteTableDef()
@@ -10,14 +10,14 @@
# 基础返回
@routes.get('/')
-def hello_world(request): # put application's code here
+async def hello_world(request): # put application's code here
print(f"[{GetTime()}] [request] /")
return web.Response(body=json.dumps(
{
'code': 0,
- 'message': 'Hello! Use path /shop-url or /shop-img to get valorant daily shop',
+ 'message': 'Hello! Use path /shop or /shop-img to get valorant daily shop',
'info':
- '在path后添加/shop-img或者/shop-url来获取每日商店,前者会直接跳转,后者返回一个带图片url的json。示例: /shop-url?account=Riot账户&passwd=Riot密码&img_src=可选参数,自定义背景图',
+ '在path后添加/shop-img或者/shop来获取每日商店,前者会直接跳转,后者返回一个带图片url的json。示例: /shop?account=Riot账户&passwd=Riot密码&img_src=可选参数,自定义背景图',
'docs': 'https://github.com/Aewait/Kook-Valorant-Bot/blob/main/docs/valorant-shop-img-api.md'
},
indent=2,
@@ -29,15 +29,15 @@ def hello_world(request): # put application's code here
# 提供4个皮肤uuid,返回图片
@routes.get('/shop-draw')
-async def get_dailshop_img(request):
+async def get_shop_draw(request):
print(f"[{GetTime()}] [request] /shop-draw")
try:
- ret = await img_draw_request(request)
+ ret = await ApiHandler.img_draw_request(request)
return web.Response(body=json.dumps(ret, indent=2, sort_keys=True, ensure_ascii=False),
content_type='application/json',status=200)
except:
err_cur = traceback.format_exc()
- print(f"[{GetTime()}] [Api] ERR in /shop-url\n{err_cur}")
+ print(f"[{GetTime()}] [Api] ERR in /shop\n{err_cur}")
return web.Response(body=json.dumps(
{
'code': 200,
@@ -54,10 +54,10 @@ async def get_dailshop_img(request):
# 直接跳转图片(浏览器访问,get方法不安全)
@routes.get('/shop-img')
-async def get_dailshop_img(request):
+async def get_shop_img(request):
print(f"[{GetTime()}] [request] /shop-img")
try:
- ret = await login_img_request(request)
+ ret = await ApiHandler.login_request(request,"GET")
if ret['code'] == 0:
return web.Response(headers={'Location': ret['message']}, status=303) # 303是直接跳转到图片
else:
@@ -80,17 +80,17 @@ async def get_dailshop_img(request):
content_type='application/json')
-# 获取图片url
-@routes.post('/shop')
-async def get_dailshop_img(request):
- print(f"[{GetTime()}] [request] /shop")
+# 登录接口
+@routes.post('/login')
+async def post_login(request):
+ print(f"[{GetTime()}] [request] /login")
try:
- ret = await login_img_request(request,"POST")
+ ret = await ApiHandler.login_request(request,"POST")
return web.Response(body=json.dumps(ret, indent=2, sort_keys=True, ensure_ascii=False),
content_type='application/json',status=200)
except:
err_cur = traceback.format_exc()
- print(f"[{GetTime()}] [Api] ERR in /shop-url\n{err_cur}")
+ print(f"[{GetTime()}] [Api] ERR in /shop\n{err_cur}")
return web.Response(body=json.dumps(
{
'code': 200,
@@ -104,12 +104,12 @@ async def get_dailshop_img(request):
status=200,
content_type='application/json')
-
+# 邮箱验证登录
@routes.post('/tfa')
async def post_tfa_code(request):
print(f"[{GetTime()}] [request] /tfa")
try:
- ret = await tfa_code_requeset(request)
+ ret = await ApiHandler.tfa_code_requeset(request)
return web.Response(body=json.dumps(ret, indent=2, sort_keys=True, ensure_ascii=False),
content_type='application/json',status=200)
except:
@@ -127,17 +127,77 @@ async def post_tfa_code(request):
ensure_ascii=False),
status=200,
content_type='application/json')
+
+@routes.post('/shop')
+async def post_shop(request):
+ print(f"[{GetTime()}] [request] /shop")
+ try:
+ body = await request.content.read()
+ params = json.loads(body.decode('UTF8'))
+ # 判断必须要的参数是否齐全
+ if 'account' not in params or 'token' not in params: # 不全,报错
+ print(f"ERR! [{GetTime()}] params needed: token/account/passwd")
+ ret = {
+ 'code': 400,
+ 'message': 'params needed: token/account/passwd',
+ 'info': '缺少参数!示例: /shop-img?token=api凭证&account=Riot账户&passwd=Riot密码&img_src=自定义背景图(可选)',
+ 'docs': 'https://github.com/Aewait/Kook-Valorant-Bot/blob/main/docs/valorant-shop-img-api.md'
+ }
+ return web.Response(body=json.dumps(ret, indent=2, sort_keys=True, ensure_ascii=False),
+ content_type='application/json',status=200)
+ # 画图请求,不需要检测token速率
+ ret = await ApiHandler.shop_get_request(params,params['account'])
+ return web.Response(body=json.dumps(ret, indent=2, sort_keys=True, ensure_ascii=False),
+ content_type='application/json',status=200)
+ except:
+ err_cur = traceback.format_exc()
+ print(f"[{GetTime()}] [Api] ERR in /shop\n{err_cur}")
+ return web.Response(body=json.dumps(
+ {
+ 'code': 200,
+ 'message': 'unkown err',
+ 'info': f'未知错误',
+ 'except': f'{err_cur}'
+ },
+ indent=2,
+ sort_keys=True,
+ ensure_ascii=False),
+ status=200,
+ content_type='application/json')
+# 用于控制db中ShopCmp的更新
+@routes.post('/shop-cmp')
+async def post_shop_cmp(request):
+ print(f"[{GetTime()}] [request] /shop-cmp")
+ try:
+ ret = await ApiHandler.shop_cmp_request(request)
+ return web.Response(body=json.dumps(ret, indent=2, sort_keys=True, ensure_ascii=False),
+ content_type='application/json',status=200)
+ except:
+ err_cur = traceback.format_exc()
+ print(f"[{GetTime()}] [Api] ERR in /shop-cmp\n{err_cur}")
+ return web.Response(body=json.dumps(
+ {
+ 'code': 200,
+ 'message': 'unkown err',
+ 'info': f'未知错误',
+ 'except': f'{err_cur}'
+ },
+ indent=2,
+ sort_keys=True,
+ ensure_ascii=False),
+ status=200,
+ content_type='application/json')
-from main import bot
# 爱发电的wh
+from main import bot
@routes.post('/afd')
async def aifadian_webhook(request):
print(f"[{GetTime()}] [request] /afd")
try:
- ret = await afd_request(request, bot)
+ ret = await ApiHandler.afd_request(request, bot)
return web.Response(body=json.dumps(ret, indent=2, sort_keys=True, ensure_ascii=False),
content_type='application/json')
except:
diff --git a/code/config/config.exp.json b/code/config/config.exp.json
index 423caac..4b0eae7 100644
--- a/code/config/config.exp.json
+++ b/code/config/config.exp.json
@@ -16,7 +16,11 @@
},
"leancloud":{
"appid":"leancloud数据库的appid(可联系作者,共用皮肤评价数据库)",
- "master_key":"leancloud数据库的masterkey"
+ "appkey":"leancloud数据库的appkey",
+ "master_key":"leancloud数据库的masterkey",
+ "user_name":"数据库内置用户id",
+ "user_pwd":"数据库内置用户密码"
},
- "no":1000
+ "no":1000,
+ "platform":"kook"
}
\ No newline at end of file
diff --git a/code/main.py b/code/main.py
index 6b4a319..2a7f9de 100644
--- a/code/main.py
+++ b/code/main.py
@@ -1,7 +1,5 @@
# encoding: utf-8:
-import json
-import os
-import io
+import os, io
import random
import time
import traceback
@@ -11,34 +9,21 @@
import copy
import zhconv
import asyncio
-import threading
-from khl import (Bot, Event, EventTypes, Message, PrivateMessage, requester)
+from khl import (Bot, Event, EventTypes, Message, PrivateMessage, requester,Channel)
from khl.card import Card, CardMessage, Element, Module, Types, Struct
-from khl.command import Rule
from aiohttp import client_exceptions
-from PIL import Image, UnidentifiedImageError # 用于合成图片
-from riot_auth import RiotAuth, auth_exceptions
-
-from utils import ShopRate
-from utils.Help import help_main, help_val, help_develop
-from utils.BotLog import logging, log_bot_list, log_bot_user, log_bot_list_text, APIRequestFailed_Handler, BaseException_Handler,get_proc_info
-from utils.Other import weather
-from utils.KookApi import (icon_cm, status_active_game, status_active_music, status_delete, bot_offline, upd_card,
- get_card)
-from utils.GrantRoles import (Color_GrantRole, Color_SetGm, Color_SetMsg, THX_Sponser)
-from utils.valorant.Val import *
-from utils.valorant.EzAuth import auth2fa, authflow, auth2faWait, Get2faWait_Key, User2faCode,EzAuthExp
-from utils.Gtime import GetTime, GetTimeStampOf8AM
-from utils.BotVip import (VipUserDict, create_vip_uuid, fetch_vip_user, roll_vip_start, using_vip_uuid, vip_ck,
- vip_time_remain, vip_time_remain_cm, vip_time_stamp,get_vip_shop_bg_cm,replace_illegal_img,illegal_img_169)
-from utils.Translate import ListTL, translate_main, Shutdown_TL, checkTL, Open_TL, Close_TL
-from utils.ShopImg import get_shop_img_11, get_shop_img_169, img_requestor
-from utils.valorant.ValFileUpd import update_bundle_url, update_price, update_skins
+from PIL import Image, UnidentifiedImageError # 用于合成图片
+
+from .utils import ShopRate, ShopImg, Help, GrantRoles, Translate, BotVip, BotLog, Other
+from .utils.valorant import ValFileUpd
+from .utils.KookApi import (icon_cm, status_active_game, status_active_music, status_delete, bot_offline, upd_card,
+ get_card)
+from .utils.valorant.Val import *
+from .utils.valorant.EzAuth import EzAuth, EzAuthExp
+from .utils.Gtime import GetTime, GetTimeStampOf8AM
# bot的token文件
-from utils.FileManage import config, Save_All_File
-# 用读取来的 config 初始化 bot,字段对应即可
-bot = Bot(token=config['token']['bot'])
+from .utils.FileManage import config,bot,ApiAuthLog,Save_All_File
# 只用来上传图片的bot
bot_upimg = Bot(token=config['token']['img_upload_token'])
@@ -46,8 +31,8 @@
master_id = config['master_id']
#在bot一开机的时候就获取log频道作为全局变量
-debug_ch = None
-cm_send_test = None
+debug_ch:Channel
+cm_send_test:Channel
NOTIFY_NUM = 3 # 非vip用户皮肤提醒栏位
VIP_BG_SIZE = 4 # vip用户背景图片数量限制
RATE_LIMITED_TIME = 180 # 全局登录速率超速等待秒数
@@ -77,9 +62,9 @@ async def Save_File_Task():
@bot.command(name='kill')
-async def KillBot(msg: Message,num:str, *arg):
- logging(msg)
- if msg.author_id == master_id and int(num)==config['no']:
+async def KillBot(msg: Message, num: str = '124124', *arg):
+ BotLog.logging(msg)
+ if msg.author_id == master_id and int(num) == config['no']:
# 保存所有文件
await Save_All_File(False)
await msg.reply(f"[KILL] 保存全局变量成功,bot下线")
@@ -97,53 +82,47 @@ async def KillBot(msg: Message,num:str, *arg):
# hello命令,一般用于测试阿狸在不在线
@bot.command(name='hello', aliases=['HELLO'])
async def world(msg: Message):
- logging(msg)
+ BotLog.logging(msg)
await msg.reply('你好呀~')
# help命令,触发指令为 `/Ahri`,因为help指令和其他机器人冲突
@bot.command(name='Ahri', aliases=['ahri', '阿狸'])
async def Ahri(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
- cm = help_main(start_time)
+ cm = Help.help_main(start_time)
await msg.reply(cm)
except Exception as result:
- await BaseException_Handler("ahri", traceback.format_exc(), msg, bot, None, None, "建议加入帮助频道找我康康到底是啥问题")
- err_str = f"ERR! [{GetTime()}] ahri\n```\n{traceback.format_exc()}\n```"
- #发送错误信息到指定频道
- await bot.client.send(debug_ch, err_str)
+ await BotLog.BaseException_Handler("ahri", traceback.format_exc(),msg,debug_send=debug_ch)
# help命令(瓦洛兰特相关)
@bot.command(name='Vhelp', aliases=['vhelp'])
async def Vhelp(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
- cm = help_val()
+ cm = Help.help_val()
await msg.reply(cm)
except Exception as result:
- await BaseException_Handler("vhelp", traceback.format_exc(), msg, bot, None, None, "建议加入帮助频道找我康康到底是啥问题")
- err_str = f"ERR! [{GetTime()}] vhelp\n```\n{traceback.format_exc()}\n```"
- #发送错误信息到指定频道
- await bot.client.send(debug_ch, err_str)
+ await BotLog.BaseException_Handler("vhelp", traceback.format_exc(),msg,debug_send=debug_ch)
# 当有人@机器人的时候进行回复,可识别出是否为机器人作者
-@bot.command(regex=r'(.+)', rules=[Rule.is_bot_mentioned(bot)])
-async def atAhri(msg: Message, mention_str: str):
- logging(msg)
+@bot.on_message()
+async def atAhri(msg: Message):
try:
- if msg.author_id == master_id:
- text = help_develop()
- await msg.reply(text)
- else:
- await msg.reply(f"呀,听说有人想我了,是吗?\n输入`/ahri`打开帮助面板,和阿狸一起玩吧!")
- print(f"[atAhri] Au:{msg.author_id} msg.reply success!")
+ me = await bot.client.fetch_me()
+ if f"(met){me.id}(met)" in msg.content:
+ BotLog.logging(msg)
+ if msg.author_id == master_id:
+ text = Help.help_develop()
+ await msg.reply(text)
+ else:
+ await msg.reply(f"呀,听说有人想我了,是吗?\n输入`/ahri` 或 `/vhelp` 打开帮助面板,和阿狸一起玩吧!")
+ print(f"[atAhri] Au:{msg.author_id} msg.reply success!")
except:
- err_str = f"ERR! [{GetTime()}] atAhri\n```\n{traceback.format_exc()}\n```"
- await msg.reply(f"{err_str}")
- print(err_str)
+ await BotLog.BaseException_Handler("at_help", traceback.format_exc(),msg)
#################################################################################################
@@ -153,7 +132,7 @@ async def atAhri(msg: Message, mention_str: str):
# 倒计时函数,单位为秒,默认60秒
@bot.command()
async def countdown(msg: Message, time: int = 60, *args):
- logging(msg)
+ BotLog.logging(msg)
if args != ():
await msg.reply(f"参数错误,countdown命令只支持1个参数\n正确用法: `/countdown 120` 生成一个120s的倒计时")
return
@@ -168,16 +147,13 @@ async def countdown(msg: Message, time: int = 60, *args):
cm.append(c1)
await msg.reply(cm)
except Exception as result:
- await BaseException_Handler("countdown", traceback.format_exc(), msg, bot, None, None, "建议加入帮助频道找我康康到底是啥问题")
- err_str = f"ERR! [{GetTime()}] countdown\n```\n{traceback.format_exc()}\n```"
- #发送错误信息到指定频道
- await bot.client.send(debug_ch, err_str)
+ await BotLog.BaseException_Handler("countdown", traceback.format_exc(), msg,debug_send=debug_ch)
# 掷骰子 saying `!roll 1 100` in channel,or `/roll 1 100 5` to dice 5 times once
@bot.command()
async def roll(msg: Message, t_min: int = 1, t_max: int = 100, n: int = 1, *args):
- logging(msg)
+ BotLog.logging(msg)
if args != ():
await msg.reply(
f"参数错误,roll命令只支持3个参数\n正确用法:\n```\n/roll 1 100 生成一个1到100之间的随机数\n/roll 1 100 3 生成三个1到100之间的随机数\n```")
@@ -192,27 +168,21 @@ async def roll(msg: Message, t_min: int = 1, t_max: int = 100, n: int = 1, *args
result = [random.randint(t_min, t_max) for i in range(n)]
await msg.reply(f'掷出来啦: {result}')
except Exception as result:
- await BaseException_Handler("roll", traceback.format_exc(), msg, bot, None, None, "建议加入帮助频道找我康康到底是啥问题")
- err_str = f"ERR! [{GetTime()}] roll\n```\n{traceback.format_exc()}\n```"
- #发送错误信息到指定频道
- await bot.client.send(debug_ch, err_str)
+ await BotLog.BaseException_Handler("roll", traceback.format_exc(), msg,debug_send=debug_ch)
# 返回天气
@bot.command(name='we')
async def Weather(msg: Message, city: str = "err"):
- logging(msg)
+ BotLog.logging(msg)
if city == "err":
await msg.reply(f"函数参数错误,城市: `{city}`\n")
return
try:
- await weather(msg, city)
+ await Other.weather(msg, city)
except Exception as result:
- await BaseException_Handler("Weather", traceback.format_exc(), msg, bot, None, None, "建议加入帮助频道找我康康到底是啥问题")
- err_str = f"ERR! [{GetTime()}] Weather\n```\n{traceback.format_exc()}\n```"
- #发送错误信息到指定频道
- await bot.client.send(debug_ch, err_str)
+ await BotLog.BaseException_Handler("Weather", traceback.format_exc(), msg,debug_send=debug_ch)
################################ grant roles for user ##########################################
@@ -221,29 +191,29 @@ async def Weather(msg: Message, city: str = "err"):
# 在不修改代码的前提下设置上色功能的服务器和监听消息
@bot.command()
async def Color_Set_GM(msg: Message, Card_Msg_id: str):
- logging(msg)
+ BotLog.logging(msg)
if msg.author_id == master_id:
- await Color_SetGm(msg, Card_Msg_id)
+ await GrantRoles.Color_SetGm(msg, Card_Msg_id)
# 判断消息的emoji回应,并给予不同角色
@bot.on_event(EventTypes.ADDED_REACTION)
async def Grant_Roles(b: Bot, event: Event):
- await Color_GrantRole(b, event)
+ await GrantRoles.Color_GrantRole(b, event)
# 给用户上色(在发出消息后,机器人自动添加回应)
@bot.command(name='Color_Set', aliases=['color_set'])
async def Color_Set(msg: Message):
- logging(msg)
+ BotLog.logging(msg)
if msg.author_id == master_id:
- await Color_SetMsg(bot, msg)
+ await GrantRoles.Color_SetMsg(bot, msg)
# 感谢助力者(每天19点进行检查)
@bot.task.add_cron(hour=19, minute=0, timezone="Asia/Shanghai")
async def thanks_sponser():
- await THX_Sponser(bot)
+ await GrantRoles.THX_Sponser(bot)
######################################## Translate ################################################
@@ -252,51 +222,51 @@ async def thanks_sponser():
# 普通翻译指令
@bot.command(name='TL', aliases=['tl'])
async def translation(msg: Message, *arg):
- logging(msg)
- await translate_main(msg, ' '.join(arg))
+ BotLog.logging(msg)
+ await Translate.translate_main(msg, ' '.join(arg))
#查看当前占用的实时翻译栏位
@bot.command()
async def CheckTL(msg: Message):
- logging(msg)
- await msg.reply(f"目前已使用栏位:{checkTL()}/{len(ListTL)}")
+ BotLog.logging(msg)
+ await msg.reply(f"目前已使用栏位:{Translate.checkTL()}/{len(Translate.ListTL)}")
# 关闭所有栏位的实时翻译(避免有些人用完不关)
@bot.command(name='ShutdownTL', aliases=['SDTL'])
async def ShutdownTL(msg: Message):
- logging(msg)
+ BotLog.logging(msg)
if msg.author.id != master_id:
return #这条命令只有bot的作者可以调用
- await Shutdown_TL(bot, msg)
+ await Translate.Shutdown_TL(bot, msg)
# 通过频道id判断是否实时翻译本频道内容
@bot.command(regex=r'(.+)')
async def TL_Realtime(msg: Message, *arg):
- if msg.ctx.channel.id in ListTL: #判断频道是否已开启实时翻译
+ if msg.ctx.channel.id in Translate.ListTL: #判断频道是否已开启实时翻译
word = " ".join(arg)
# 不翻译关闭实时翻译的指令
if word == "/TLOFF" or word == "/tloff" or word == '/tlon' or word == '/TLON':
return
# 翻译
- logging(msg)
- await translate_main(msg, ' '.join(arg))
+ BotLog.logging(msg)
+ await Translate.translate_main(msg, ' '.join(arg))
# 开启实时翻译功能
@bot.command(name='TLON', aliases=['tlon'])
async def TLON(msg: Message):
- logging(msg)
- await Open_TL(msg)
+ BotLog.logging(msg)
+ await Translate.Open_TL(msg)
# 关闭实时翻译功能
@bot.command(name='TLOFF', aliases=['tloff'])
async def TLOFF(msg: Message):
- logging(msg)
- await Close_TL(msg)
+ BotLog.logging(msg)
+ await Translate.Close_TL(msg)
###########################################################################################
@@ -307,7 +277,7 @@ async def TLOFF(msg: Message):
# 开始打游戏
@bot.command()
async def gaming(msg: Message, game: int = 1):
- logging(msg)
+ BotLog.logging(msg)
#await bot.client.update_playing_game(3,1)# 英雄联盟
if game == 1:
ret = await status_active_game(453027) # 瓦洛兰特
@@ -320,7 +290,7 @@ async def gaming(msg: Message, game: int = 1):
# 开始听歌
@bot.command()
async def singing(msg: Message, music: str = "err", singer: str = "err"):
- logging(msg)
+ BotLog.logging(msg)
if music == "err" or singer == "err":
await msg.reply(f"函数参数错误,music: `{music}` singer: `{singer}`")
return
@@ -332,7 +302,7 @@ async def singing(msg: Message, music: str = "err", singer: str = "err"):
# 停止打游戏1/听歌2
@bot.command(name='sleeping')
async def sleeping(msg: Message, d: int = 1):
- logging(msg)
+ BotLog.logging(msg)
ret = await status_delete(d)
if d == 1:
await msg.reply(f"{ret['message']},阿狸下号休息啦!")
@@ -352,7 +322,7 @@ async def Login_Forbidden_send(msg: Message):
# 手动设置禁止登录的全局变量状态
@bot.command(name='lf')
async def Login_Forbidden_Change(msg: Message):
- logging(msg)
+ BotLog.logging(msg)
if msg.author_id == master_id:
global Login_Forbidden
if Login_Forbidden:
@@ -366,7 +336,7 @@ async def Login_Forbidden_Change(msg: Message):
# 存储用户游戏id
@bot.command()
async def saveid(msg: Message, *args):
- logging(msg)
+ BotLog.logging(msg)
if args == ():
await msg.reply(f"您没有提供您的游戏id:`{args}`")
return
@@ -382,7 +352,7 @@ async def saveid(msg: Message, *args):
# 已保存id总数
@bot.command(name='saveid-a')
async def saveid_all(msg: Message):
- logging(msg)
+ BotLog.logging(msg)
try:
await saveid_count(msg)
except Exception as result:
@@ -394,7 +364,7 @@ async def saveid_all(msg: Message):
# 实现读取用户游戏ID并返回
@bot.command(name="myid", aliases=['MYID']) # 这里的aliases是别名
async def myid(msg: Message, *args):
- logging(msg)
+ BotLog.logging(msg)
if args != ():
await msg.reply(f"`/myid`命令不需要参数!")
return
@@ -410,7 +380,7 @@ async def myid(msg: Message, *args):
# 查询游戏错误码
@bot.command(name='val', aliases=['van', 'VAN', 'VAL'])
async def val_err(msg: Message, numS: str = "-1", *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
await val_errcode(msg, numS)
except Exception as result:
@@ -420,22 +390,23 @@ async def val_err(msg: Message, numS: str = "-1", *arg):
#关于dx报错的解决方法
@bot.command(name='DX', aliases=['dx']) # 新增别名dx
async def dx(msg: Message):
- logging(msg)
+ BotLog.logging(msg)
await dx123(msg)
###########################################vip######################################################
#用来存放roll的频道/服务器/回应用户的dict
-from utils.FileManage import VipShopBgDict,VipRollDcit,UserApLog
+from utils.FileManage import VipShopBgDict, VipRollDcit, UserPwdReauth,VipUserDict
+
# 新建vip的uuid,第一个参数是天数,第二个参数是数量
@bot.command(name="vip-a")
async def get_vip_uuid(msg: Message, day: int = 30, num: int = 10):
- logging(msg)
+ BotLog.logging(msg)
try:
if msg.author_id == master_id:
- text = await create_vip_uuid(num, day)
+ text = await BotVip.create_vip_uuid(num, day)
cm = CardMessage()
c = Card(Module.Header(f"已生成新的uuid 数量:{num} 天数:{day}"),
Module.Divider(),
@@ -455,47 +426,40 @@ async def get_vip_uuid(msg: Message, day: int = 30, num: int = 10):
# 兑换vip
@bot.command(name="vip-u", aliases=['兑换'])
async def buy_vip_uuid(msg: Message, uuid: str = 'err', *arg):
- logging(msg)
+ BotLog.logging(msg)
if uuid == 'err':
await msg.reply(f"只有输入vip的兑换码才可以操作哦!uuid: `{uuid}`")
return
try:
#把bot传过去是为了让阿狸在有人成兑换激活码之后发送消息到log频道
- ret = await using_vip_uuid(msg, uuid, bot, debug_ch)
+ ret = await BotVip.using_vip_uuid(msg, uuid, bot, debug_ch)
global VipShopBgDict #在用户兑换vip的时候就创建此键值
VipShopBgDict['cache'][msg.author_id] = {'cache_time': 0, 'cache_img': None}
except Exception as result:
- await BaseException_Handler("vip-u", traceback.format_exc(), msg, bot, None, None, "建议加入帮助频道找我康康到底是啥问题")
- err_str = f"ERR! [{GetTime()}] vip-u\n```\n{traceback.format_exc()}\n```"
- #发送错误信息到指定频道
- await bot.client.send(debug_ch, err_str)
+ await BotLog.BaseException_Handler("vip-u", traceback.format_exc(), msg,debug_send=debug_ch)
# 看vip剩余时间
@bot.command(name="vip-c")
async def check_vip_timeremain(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
- if not await vip_ck(msg):
+ if not await BotVip.vip_ck(msg):
return
# 获取时间
- ret_t = vip_time_remain(msg.author_id)
- ret_cm = await vip_time_remain_cm(ret_t)
+ ret_t = BotVip.vip_time_remain(msg.author_id)
+ ret_cm = await BotVip.vip_time_remain_cm(ret_t)
await msg.reply(ret_cm)
except Exception as result:
- await BaseException_Handler("vip-c", traceback.format_exc(), msg, bot, None, None, "建议加入帮助频道找我康康到底是啥问题")
- err_str = f"ERR! [{GetTime()}] vip-c\n```\n{traceback.format_exc()}\n```"
- #发送错误信息到指定频道
- await bot.client.send(debug_ch, err_str)
-
+ await BotLog.BaseException_Handler("vip-c", traceback.format_exc(), msg,debug_send=debug_ch)
# 看vip用户列表
@bot.command(name="vip-l")
async def list_vip_user(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
if msg.author_id == master_id:
- text = await fetch_vip_user()
+ text = await BotVip.fetch_vip_user()
cm2 = CardMessage()
c = Card(Module.Header(f"当前vip用户列表如下"), color='#e17f89')
c.append(Module.Section(Element.Text(f"```\n{text}```", Types.Text.KMD)))
@@ -504,9 +468,7 @@ async def list_vip_user(msg: Message, *arg):
else:
await msg.reply("您没有权限操作此命令!")
except Exception as result:
- err_str = f"ERR! [{GetTime()}] list_vip_user\n```\n{traceback.format_exc()}\n```"
- print(err_str)
- await msg.reply(err_str)
+ await BotLog.BaseException_Handler("vip-l", traceback.format_exc(), msg)
async def check_vip_img():
@@ -526,7 +488,7 @@ async def check_vip_img():
i = 0
while i < sz:
try:
- bg_test = Image.open(io.BytesIO(await img_requestor(vip_bg["background"][i])))
+ bg_test = Image.open(io.BytesIO(await ShopImg.img_requestor(vip_bg["background"][i])))
i += 1
except UnidentifiedImageError as result:
err_str = f"ERR! [{GetTime()}] checking [{vip_user}] img\n```\n{result}\n"
@@ -536,7 +498,7 @@ async def check_vip_img():
cm0.append(c)
await user.send(cm0) # 发送私聊消息给用户
await bot.client.send(debug_ch, err_str) # 发送消息到debug频道
- vip_bg["background"][i] = illegal_img_169 #修改成16比9的图片
+ vip_bg["background"][i] = BotVip.illegal_img_169 #修改成16比9的图片
vip_bg["status"] = False #需要重新加载图片
print(err_str)
except Exception as result:
@@ -567,7 +529,7 @@ async def check_vip_img_task():
@bot.command(name="vip-img")
async def check_vip_img_task(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
if msg.author_id == master_id:
await check_vip_img()
await msg.reply("背景图片diy检查完成!")
@@ -576,18 +538,15 @@ async def check_vip_img_task(msg: Message, *arg):
return
-
-
-
@bot.command(name="vip-shop")
async def vip_shop_bg_set(msg: Message, icon: str = "err", *arg):
- logging(msg)
+ BotLog.logging(msg)
if icon != 'err' and ('http' not in icon or '](' not in icon):
await msg.reply(f"请提供正确的图片url!\n当前:`{icon}`")
return
try:
- if not await vip_ck(msg):
+ if not await BotVip.vip_ck(msg):
return
x3 = "[None]"
@@ -612,7 +571,7 @@ async def vip_shop_bg_set(msg: Message, icon: str = "err", *arg):
print(f"[vip-shop] Au:{msg.author_id} img_type_not support")
return
#打开图片(测试)
- bg_vip = Image.open(io.BytesIO(await img_requestor(x3)))
+ bg_vip = Image.open(io.BytesIO(await ShopImg.img_requestor(x3)))
except UnidentifiedImageError as result:
err_str = f"ERR! [{GetTime()}] vip_shop_imgck\n```\n{result}\n```"
print(err_str)
@@ -628,7 +587,7 @@ async def vip_shop_bg_set(msg: Message, icon: str = "err", *arg):
#插入图片
VipShopBgDict['bg'][msg.author_id]["background"].append(x3)
- cm = await get_vip_shop_bg_cm(msg)
+ cm = await BotVip.get_vip_shop_bg_cm(msg)
#先让测试bot把这个卡片发到频道,如果发出去了说明json没有问题
await bot_upimg.client.send(cm_send_test, cm)
print(f"[vip-shop] Au:{msg.author_id} cm_send_test success")
@@ -639,22 +598,22 @@ async def vip_shop_bg_set(msg: Message, icon: str = "err", *arg):
print(f"[vip-shop] Au:{msg.author_id} add ", x3)
except requester.HTTPRequester.APIRequestFailed as result:
- await APIRequestFailed_Handler("vip_shop", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.APIRequestFailed_Handler("vip_shop", traceback.format_exc(), msg, bot,cm)
VipShopBgDict['bg'][msg.author_id]["background"].remove(x3) #删掉里面的图片
print(f"[vip_shop] Au:{msg.author_id} remove(err_img)")
except Exception as result:
- await BaseException_Handler("vip_shop", traceback.format_exc(), msg, bot, None, cm, "建议加入帮助频道找我康康到底是啥问题")
+ await BotLog.BaseException_Handler("vip_shop", traceback.format_exc(), msg)
@bot.command(name="vip-shop-s")
async def vip_shop_bg_set_s(msg: Message, num: str = "err", *arg):
- logging(msg)
+ BotLog.logging(msg)
if num == 'err':
await msg.reply(f"请提供正确的图片序号!\n当前:`{num}`")
return
try:
global VipShopBgDict
- if not await vip_ck(msg):
+ if not await BotVip.vip_ck(msg):
return
if msg.author_id not in VipShopBgDict['bg']:
await msg.reply("您尚未自定义商店背景图!")
@@ -664,11 +623,11 @@ async def vip_shop_bg_set_s(msg: Message, num: str = "err", *arg):
if num < len(VipShopBgDict['bg'][msg.author_id]["background"]):
try: #打开用户需要切换的图片
bg_vip = Image.open(
- io.BytesIO(await img_requestor(VipShopBgDict['bg'][msg.author_id]["background"][num])))
+ io.BytesIO(await ShopImg.img_requestor(VipShopBgDict['bg'][msg.author_id]["background"][num])))
except UnidentifiedImageError as result:
err_str = f"ERR! [{GetTime()}] vip_shop_s_imgck\n```\n{result}\n```"
await msg.reply(f"图片违规!请重新上传\n{err_str}")
- await replace_illegal_img(msg.author_id, num) #替换图片
+ await BotVip.replace_illegal_img(msg.author_id, num) #替换图片
print(err_str)
return
# 图片检查通过,交换两个图片的位置
@@ -681,7 +640,7 @@ async def vip_shop_bg_set_s(msg: Message, num: str = "err", *arg):
await msg.reply("请提供正确返回的图片序号,可以用`/vip-shop`进行查看")
return
- cm = await get_vip_shop_bg_cm(msg)
+ cm = await BotVip.get_vip_shop_bg_cm(msg)
#先让测试bot把这个卡片发到频道,如果发出去了说明json没有问题
await bot_upimg.client.send(cm_send_test, cm)
print(f"[vip-shop] Au:{msg.author_id} cm_send_test success")
@@ -690,19 +649,19 @@ async def vip_shop_bg_set_s(msg: Message, num: str = "err", *arg):
print(f"[vip-shop-s] Au:{msg.author_id} switch to [{VipShopBgDict['bg'][msg.author_id]['background'][0]}]")
except requester.HTTPRequester.APIRequestFailed as result:
- await APIRequestFailed_Handler("vip_shop_s", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.APIRequestFailed_Handler("vip_shop_s", traceback.format_exc(), msg, bot, cm)
except Exception as result:
- await BaseException_Handler("vip_shop_s", traceback.format_exc(), msg, bot, None, cm, "您可能需要重新执行操作")
+ await BotLog.BaseException_Handler("vip_shop_s", traceback.format_exc(), msg)
@bot.command(name="vip-shop-d")
async def vip_shop_bg_set_d(msg: Message, num: str = "err", *arg):
- logging(msg)
+ BotLog.logging(msg)
if num == 'err':
await msg.reply(f"请提供正确的图片序号!\n当前:`{num}`")
return
try:
- if not await vip_ck(msg):
+ if not await BotVip.vip_ck(msg):
return
if msg.author_id not in VipShopBgDict['bg']:
await msg.reply("您尚未自定义商店背景图!")
@@ -720,7 +679,7 @@ async def vip_shop_bg_set_d(msg: Message, num: str = "err", *arg):
await msg.reply("请提供正确返回的图片序号,可以用`/vip-shop`进行查看")
return
- cm = await get_vip_shop_bg_cm(msg)
+ cm = await BotVip.get_vip_shop_bg_cm(msg)
#先让测试bot把这个卡片发到频道,如果发出去了说明json没有问题
await bot_upimg.client.send(cm_send_test, cm)
print(f"[vip-shop] Au:{msg.author_id} cm_send_test success")
@@ -729,9 +688,9 @@ async def vip_shop_bg_set_d(msg: Message, num: str = "err", *arg):
print(f"[vip-shop-d] Au:{msg.author_id} delete [{del_img_url}]")
except requester.HTTPRequester.APIRequestFailed as result:
- await APIRequestFailed_Handler("vip_shop_d", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.APIRequestFailed_Handler("vip_shop_d", traceback.format_exc(), msg, bot, cm)
except Exception as result:
- await BaseException_Handler("vip_shop_d", traceback.format_exc(), msg, bot, None, cm, "您可能需要重新执行操作")
+ await BotLog.BaseException_Handler("vip_shop_d", traceback.format_exc(), msg)
# 判断消息的emoji回应,并记录id
@@ -756,23 +715,27 @@ async def vip_roll_log(b: Bot, event: Event):
# 开启一波抽奖
@bot.command(name='vip-r', aliases=['vip-roll'])
async def vip_roll(msg: Message, vday: int = 7, vnum: int = 5, rday: float = 1.0):
- logging(msg)
- if msg.author_id != master_id:
- await msg.reply(f"您没有权限执行本命令")
- return
- # 设置开始抽奖
- global VipRollDcit
- cm = roll_vip_start(vnum, vday, rday)
- roll_ch = await bot.client.fetch_public_channel(msg.ctx.channel.id)
- roll_send = await bot.client.send(roll_ch, cm)
- VipRollDcit[roll_send['msg_id']] = {}
- VipRollDcit[roll_send['msg_id']]['time'] = time.time() + rday * 86400
- VipRollDcit[roll_send['msg_id']]['nums'] = vnum
- VipRollDcit[roll_send['msg_id']]['days'] = vday
- VipRollDcit[roll_send['msg_id']]['channel_id'] = msg.ctx.channel.id
- VipRollDcit[roll_send['msg_id']]['guild_id'] = msg.ctx.guild.id
- VipRollDcit[roll_send['msg_id']]['user'] = list()
- print(f"[vip-roll] card message send to {msg.ctx.channel.id}")
+ BotLog.logging(msg)
+ try:
+ if msg.author_id != master_id:
+ await msg.reply(f"您没有权限执行本命令")
+ return
+ # 设置开始抽奖
+ global VipRollDcit
+ cm = BotVip.roll_vip_start(vnum, vday, rday)
+ roll_ch = await bot.client.fetch_public_channel(msg.ctx.channel.id)
+ roll_send = await bot.client.send(roll_ch, cm)
+ VipRollDcit[roll_send['msg_id']] = { # type: ignore
+ 'time': time.time() + rday * 86400,
+ 'nums': vnum,
+ 'days': vday,
+ 'channel_id': msg.ctx.channel.id,
+ 'guild_id': msg.ctx.guild.id,
+ 'user': []
+ }
+ print(f"[vip-roll] card message send to {msg.ctx.channel.id}")
+ except:
+ await BotLog.BaseException_Handler("vip-r",traceback.format_exc(),msg)
@bot.task.add_interval(seconds=80)
@@ -785,22 +748,22 @@ async def vip_roll_task():
continue
else:
print(f"[BOT.TASK] vip_roll_task msg:{msg_id}")
- vday = VipRollDcit[msg_id]['days'] # vip天数
- vnum = VipRollDcit[msg_id]['nums'] # 奖品数量
+ vday = VipRollDcit[msg_id]['days'] # vip天数
+ vnum = VipRollDcit[msg_id]['nums'] # 奖品数量
# 结束抽奖
log_str = f"```\n[MsgID] {msg_id}\n"
send_str = "恭喜 "
# 人数大于奖品数量
- if len(VipRollDcit[msg_id]['user'])>vnum:
- ran = random.sample(range(0, len(VipRollDcit[msg_id]['user'])), vnum) # 生成n个随机数
- else: # 生成一个从0到len-1的列表 如果只有一个用户,生成的是[0]
+ if len(VipRollDcit[msg_id]['user']) > vnum:
+ ran = random.sample(range(0, len(VipRollDcit[msg_id]['user'])), vnum) # 生成n个随机数
+ else: # 生成一个从0到len-1的列表 如果只有一个用户,生成的是[0]
ran = list(range(len(VipRollDcit[msg_id]['user'])))
# 开始遍历
for j in ran:
user_id = VipRollDcit[msg_id]['user'][j]
user = await bot.client.fetch_user(user_id)
# 设置用户的时间和个人信息
- time_vip = vip_time_stamp(user_id, vday)
+ time_vip = BotVip.vip_time_stamp(user_id, vday)
VipUserDict[user_id] = {'time': time_vip, 'name_tag': f"{user.username}#{user.identify_num}"}
# 创建卡片消息
cm = CardMessage()
@@ -809,7 +772,7 @@ async def vip_roll_task():
Element.Image(src=icon_cm.ahri_kda2, size='sm')))
c.append(Module.Context(Element.Text(f"您抽中了{vday}天vip,可用/vhelp查看vip权益", Types.Text.KMD)))
c.append(
- Module.Countdown(datetime.now() + timedelta(seconds=vip_time_remain(user_id)),
+ Module.Countdown(datetime.now() + timedelta(seconds=BotVip.vip_time_remain(user_id)),
mode=Types.CountdownMode.DAY))
c.append(Module.Divider())
c.append(
@@ -841,7 +804,7 @@ async def vip_roll_task():
# 给所有vip用户添加时间,避免出现某些错误的时候浪费vip时间
@bot.command(name='vip-ta')
async def vip_time_add(msg: Message, vday: int = 1, *arg):
- logging(msg)
+ BotLog.logging(msg)
if msg.author_id != master_id:
await msg.reply(f"您没有权限执行此命令!")
return
@@ -850,7 +813,7 @@ async def vip_time_add(msg: Message, vday: int = 1, *arg):
global VipUserDict
# 给所有vip用户上天数
for vip, vinfo in VipUserDict.items():
- time_vip = vip_time_stamp(vip, vday)
+ time_vip = BotVip.vip_time_stamp(vip, vday)
VipUserDict[vip]['time'] = time_vip
await msg.reply(f"操作完成,已给所有vip用户增加 `{vday}` 天时长")
@@ -864,7 +827,7 @@ async def vip_time_add(msg: Message, vday: int = 1, *arg):
#####################################################################################
# 预加载用户的riot游戏id和玩家uuid(登录后Api获取)
-from utils.FileManage import UserTokenDict,SkinNotifyDict,EmojiDict,SkinRateDict
+from utils.FileManage import UserRiotName, SkinNotifyDict, EmojiDict, SkinRateDict,ValBundleList
# 用来存放auth对象(无法直接保存到文件)
UserAuthDict = {'AP': {}}
@@ -888,11 +851,13 @@ def check_rate_err_user(user_id: str):
"""
return (user_id in SkinRateDict['err_user'])
+
# 判断uuid是否相等(用户有没有切换登录账户)
def isSame_Authuuid(msg: Message):
- """UserShopDict[msg.author_id]["auth_user_id"] == UserTokenDict[msg.author_id]["auth_user_id"]
+ """UserShopDict[msg.author_id]["auth_user_id"] == UserRiotName[msg.author_id]["auth_user_id"]
"""
- return UserShopDict[msg.author_id]["auth_user_id"] == UserTokenDict[msg.author_id]["auth_user_id"]
+ return UserShopDict[msg.author_id]["auth_user_id"] == UserRiotName[msg.author_id]["auth_user_id"]
+
# 检查全局用户登录速率
async def check_GloginRate():
@@ -908,7 +873,7 @@ async def check_GloginRate():
#查询当前有多少用户登录了
@bot.command(name="ckau")
async def check_UserAuthDict_len(msg: Message):
- logging(msg)
+ BotLog.logging(msg)
sz = len(UserAuthDict)
res = f"UserAuthDict_len: `{sz}`"
print(res)
@@ -919,8 +884,8 @@ async def check_UserAuthDict_len(msg: Message):
@bot.command(name='login')
async def login(msg: Message, user: str = 'err', passwd: str = 'err', apSave='', *arg):
print(f"[{GetTime()}] Au:{msg.author_id}_{msg.author.username}#{msg.author.identify_num} = /login {apSave}")
- log_bot_user(msg.author_id) #这个操作只是用来记录用户和cmd总数的
- global Login_Forbidden, login_rate_limit, UserTokenDict, UserAuthDict
+ BotLog.log_bot_user(msg.author_id) #这个操作只是用来记录用户和cmd总数的
+ global Login_Forbidden, login_rate_limit, UserRiotName, UserAuthDict
if not isinstance(msg, PrivateMessage): # 不是私聊的话,禁止调用本命令
await msg.reply(f"为了避免您的账户信息泄漏,请「私聊」使用本命令!\n用法:`/login 账户 密码`")
return
@@ -938,38 +903,34 @@ async def login(msg: Message, user: str = 'err', passwd: str = 'err', apSave='',
send_msg = await msg.reply(cm0) #记录消息id用于后续更新
# 3.登录,获取用户的token
- key = await Get2faWait_Key() # 先获取一个key
- # 如果使用异步运行该函数,执行流会被阻塞住等待,应该使用线程来操作
- th = threading.Thread(target=auth2fa, args=(user, passwd, key))
- th.start()
- resw = await auth2faWait(key=key, msg=msg) # 随后主执行流来这里等待
- res_auth = await resw['auth'].get_RiotAuth() # 直接获取RiotAuth对象
- is2fa = resw['auth'].is2fa # 是否是2fa用户
+ auth = EzAuth()
+ resw = await auth.authorize(user, passwd)
+ UserAuthDict[msg.author_id] = {"auth": auth, "2fa": auth.is2fa} # 将对象插入
+ # 3.1 没有成功,是2fa用户,需要执行/tfa命令
+ if not resw['status']:
+ cm1 = await get_card("登录中断,需要提供邮箱验证码", "请使用「/tfa 验证码」提供邮箱验证码", icon_cm.val_logo_gif)
+ await upd_card(send_msg['msg_id'], cm1, channel_type=msg.channel_type)
+ return
+
# 4.如果没有抛出异常,那就是完成登录了,设置用户的玩家uuid+昵称
- UserTokenDict[msg.author_id] = {
- 'auth_user_id': res_auth.user_id,
- 'GameName': resw['auth'].Name,
- 'TagLine': resw['auth'].Tag
- }
- UserAuthDict[msg.author_id] = {"auth": res_auth, "2fa": is2fa } # 将对象插入
+ UserRiotName[msg.author_id] = {'auth_user_id': auth.user_id, 'GameName': auth.Name, 'TagLine': auth.Tag}
# 设置基础打印信息
- text = f"登陆成功!欢迎回来,{UserTokenDict[msg.author_id]['GameName']}#{UserTokenDict[msg.author_id]['TagLine']}"
+ text = f"登陆成功!欢迎回来,{UserRiotName[msg.author_id]['GameName']}#{UserRiotName[msg.author_id]['TagLine']}"
info_text = "当前cookie有效期为2~3天,有任何问题请[点我](https://kook.top/gpbTwZ)"
# 5.如果是vip用户,则执行下面的代码
- if await vip_ck(msg.author_id):
+ if await BotVip.vip_ck(msg.author_id):
global VipShopBgDict #因为换了用户,所以需要修改状态码重新获取商店
if msg.author_id in VipShopBgDict['bg']:
VipShopBgDict['bg'][msg.author_id]['status'] = False
# 用于保存cookie的路径,保存vip用户登录信息
- cookie_path = f"./log/cookie/{msg.author_id}.cke"
- res_auth._cookie_jar.save(cookie_path) #保存
+ auth.save_cookies(f"./log/cookie/{msg.author_id}.cke")
# 6.用户自己选择是否保存账户密码,默认是不保存的;2fa用户也不会保存
- if apSave == 'save' and (not is2fa):
+ if apSave == 'save' and (not auth.is2fa):
# 不在这里再新建(用于保存阿狸使用账户密码重登的时间,告知用户)
- if msg.author_id not in UserApLog:
- UserApLog[msg.author_id] = {}
+ if msg.author_id not in UserPwdReauth:
+ UserPwdReauth[msg.author_id] = {}
UserAuthDict['AP'][msg.author_id] = {'a': user, 'p': passwd}
info_text += "\n您选择了保存账户密码,cookie失效后将使用账户密码重登"
@@ -979,7 +940,7 @@ async def login(msg: Message, user: str = 'err', passwd: str = 'err', apSave='',
# 8.全部都搞定了,打印登录信息日志
print(
- f"[Login] Au:{msg.author_id} - {UserTokenDict[msg.author_id]['GameName']}#{UserTokenDict[msg.author_id]['TagLine']}"
+ f"[Login] Au:{msg.author_id} - {UserRiotName[msg.author_id]['GameName']}#{UserRiotName[msg.author_id]['TagLine']}"
)
except EzAuthExp.AuthenticationError as result:
print(f"ERR! [{GetTime()}] login Au:{msg.author_id} - {result}")
@@ -988,15 +949,15 @@ async def login(msg: Message, user: str = 'err', passwd: str = 'err', apSave='',
await upd_card(send_msg['msg_id'], cm, channel_type=msg.channel_type)
except EzAuthExp.WaitOvertimeError as result:
print(f"ERR! [{GetTime()}] login Au:{msg.author_id} - {result}")
- cm = await get_card("等待超时","auth wait overtime",icon_cm.lagging)
+ cm = await get_card("等待超时", "auth wait overtime", icon_cm.lagging)
await upd_card(send_msg['msg_id'], cm, channel_type=msg.channel_type)
except EzAuthExp.RatelimitError as result:
err_str = f"ERR! [{GetTime()}] login Au:{msg.author_id} - {result}"
# 更新全局速率限制
login_rate_limit = {'limit': True, 'time': time.time()}
- print(err_str," set login_rate_limit = True")
+ print(err_str, " set login_rate_limit = True")
# 这里是第一个出现速率限制err的用户,更新消息提示
- cm = await get_card(f"登录请求超速!请在{RATE_LIMITED_TIME}s后重试", "RatelimitError,try again later",icon_cm.lagging)
+ cm = await get_card(f"登录请求超速!请在{RATE_LIMITED_TIME}s后重试", "RatelimitError,try again later", icon_cm.lagging)
await upd_card(send_msg['msg_id'], cm, channel_type=msg.channel_type)
except client_exceptions.ClientResponseError as result:
err_str = f"ERR! [{GetTime()}] login Au:{msg.author_id}\n```\n{traceback.format_exc()}\n```\n"
@@ -1023,90 +984,112 @@ async def login(msg: Message, user: str = 'err', passwd: str = 'err', apSave='',
cm = await get_card(text, text_sub, icon_cm.that_it)
await upd_card(send_msg['msg_id'], cm, channel_type=msg.channel_type)
except requester.HTTPRequester.APIRequestFailed as result: #卡片消息发送失败
- await APIRequestFailed_Handler("login", traceback.format_exc(), msg, bot, send_msg, cm)
+ await BotLog.APIRequestFailed_Handler("login", traceback.format_exc(), msg, bot, cm,send_msg=send_msg)
except Exception as result: # 其他错误
- err_str =f"[login] Au:{msg.author_id}\n```\n{traceback.format_exc()}\n```\n"
+ err_str = f"[login] Au:{msg.author_id}\n```\n{traceback.format_exc()}\n```\n"
await upd_card(send_msg['msg_id'], err_str, channel_type=msg.channel_type)
- await BaseException_Handler("login", traceback.format_exc(), msg, bot, send_msg, cm)
+ await BotLog.BaseException_Handler("login", traceback.format_exc(), msg, send_msg=send_msg,help="请加入帮助频道咨询,或尝试重新执行login命令")
@bot.command(name='tfa')
-async def tfa_verify(msg: Message, key: str, tfa: str, *arg):
- print(f"[{GetTime()}] Au:{msg.author_id}_{msg.author.username}#{msg.author.identify_num} = /2fa")
+async def tfa_verify(msg: Message, tfa: str, *arg):
+ print(f"[{GetTime()}] Au:{msg.author_id}_{msg.author.username}#{msg.author.identify_num} = /tfa")
if len(tfa) != 6:
await msg.reply(f"邮箱验证码长度错误,请确认您输入了正确的6位验证码\n当前参数:{tfa}")
return
+ send_msg = {'msg_id': ''}
try:
- global User2faCode
- key = int(key)
- if key in User2faCode:
- User2faCode[key]['vcode'] = tfa
- User2faCode[key]['2fa_status'] = True
- await msg.reply(f"两步验证码 `{tfa}` 获取成功,请等待……")
- else:
- await msg.reply(f"第二个参数key值错误,请确认您的输入,或重新login")
+ # 1. 先判断用户是否在dict里面
+ if msg.author_id not in UserAuthDict:
+ await msg.reply("您不在UserAuthDict中,请先执行login!")
+ return
+ # 1.1 在,且auth对象是ezauth
+ auth = UserAuthDict[msg.author_id]['auth']
+ assert isinstance(auth, EzAuth)
+
+ # 2.发送提示信息
+ cm0 = await get_card(f"两步验证码「{tfa}」获取成功", "小憩一下,很快就好啦!", icon_cm.val_logo_gif)
+ send_msg = await msg.reply(cm0) #记录消息id用于后续更新
+ # 3.进行邮箱验证
+ res = await auth.email_verfiy(tfa)
+ # 4.成功
+ UserRiotName[msg.author_id] = {'auth_user_id': auth.user_id, 'GameName': auth.Name, 'TagLine': auth.Tag}
+ text = f"登陆成功!欢迎回来,{UserRiotName[msg.author_id]['GameName']}#{UserRiotName[msg.author_id]['TagLine']}"
+ info_text = "当前cookie有效期为2~3天,有任何问题请[点我](https://kook.top/gpbTwZ)"
+ cm = await get_card(text, info_text, icon_cm.correct)
+ await upd_card(send_msg['msg_id'], cm, channel_type=msg.channel_type)
+
+ except EzAuthExp.MultifactorError as result:
+ if "multifactor_attempt_failed" in str(result):
+ cm = await get_card("两步验证码错误,请重试", str(result), icon_cm.lagging)
+ else:
+ cm = await get_card("邮箱验证错误,请重新login", str(result), icon_cm.lagging)
+ # 更新消息
+ await upd_card(send_msg['msg_id'], cm, channel_type=msg.channel_type)
except Exception as result: # 其他错误
- await BaseException_Handler("tfa", traceback.format_exc(), msg, bot)
+ await BotLog.BaseException_Handler("tfa", traceback.format_exc(), msg,help="请加入帮助频道咨询,或尝试重新执行login命令")
# 退出登录
@bot.command(name='logout')
async def logout(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
- global UserTokenDict, UserAuthDict
+ global UserRiotName, UserAuthDict
if msg.author_id not in UserAuthDict: #使用not in判断是否不存在
cm = await get_card("您尚未登陆!无须logout", "阿巴阿巴?", icon_cm.whats_that)
await msg.reply(cm)
return
- log_text = f"[Logout] Au:{msg.author_id} - {UserTokenDict[msg.author_id]['GameName']}#{UserTokenDict[msg.author_id]['TagLine']}"
+ log_text = f"[Logout] Au:{msg.author_id} - {UserRiotName[msg.author_id]['GameName']}#{UserRiotName[msg.author_id]['TagLine']}"
# 如果id存在,删除auth对象
- # 因为UserTokenDict里面只存放了用户游戏名/uuid,且不作为是否登录的判断,所以不需要删除
- del UserAuthDict[msg.author_id]
+ # 因为UserRiotName里面只存放了用户游戏名/uuid,且不作为是否登录的判断,所以不需要删除
+ del UserAuthDict[msg.author_id]
# 如果是vip用户,删除本地保存的cookie
cookie_path = f"./log/cookie/{msg.author_id}.cke"
# 判断路径是否存在,存在直接删除
if os.path.exists(cookie_path):
- os.remove(cookie_path) # 删除文件
- log_text+= " - rm cookie file"
+ os.remove(cookie_path) # 删除文件
+ log_text += " - rm cookie file"
- text = f"已退出登录!下次再见,{UserTokenDict[msg.author_id]['GameName']}#{UserTokenDict[msg.author_id]['TagLine']}"
+ text = f"已退出登录!下次再见,{UserRiotName[msg.author_id]['GameName']}#{UserRiotName[msg.author_id]['TagLine']}"
cm = await get_card(text, "你会回来的,对吗?", icon_cm.crying_crab)
await msg.reply(cm)
print(log_text)
except Exception as result: # 其他错误
- await BaseException_Handler("logout", traceback.format_exc(), msg, bot)
+ await BotLog.BaseException_Handler("logout", traceback.format_exc(), msg)
+
@bot.command(name='login-ap')
-async def login_acpw(msg:Message,*arg):
- logging(msg)
+async def login_acpw(msg: Message, *arg):
+ BotLog.logging(msg)
try:
- if msg.author_id not in UserApLog:
+ if msg.author_id not in UserPwdReauth:
await msg.reply(f"您没有保存账户密码或2fa用户,该命令无效")
return
- send_text='none'
- if len(UserApLog[msg.author_id]) == 0:
+ send_text = 'none'
+ if len(UserPwdReauth[msg.author_id]) == 0:
send_text = "阿狸还没有用过您的账户密码来重新登录呢"
else:
send_text = '以下为账户密码登录日志\n'
- for i in UserApLog[msg.author_id]:
- send_text+=f"{i} - {UserApLog[msg.author_id][i]}\n"
+ for i in UserPwdReauth[msg.author_id]:
+ send_text += f"{i} - {UserPwdReauth[msg.author_id][i]}\n"
# 发送信息
await msg.reply(send_text)
except Exception as result: # 其他错误
- await BaseException_Handler("login-ap", traceback.format_exc(), msg, bot)
+ await BotLog.BaseException_Handler("login-ap", traceback.format_exc(), msg)
# cookie重新登录
async def login_reauth(kook_user_id: str):
base_print = f"[{GetTime()}] Au:{kook_user_id} = "
print(base_print + "auth_token failure,trying reauthorize()")
- global UserAuthDict,UserTokenDict
+ global UserAuthDict, UserRiotName
auth = UserAuthDict[kook_user_id]['auth']
+ assert isinstance(auth, EzAuth)
#用cookie重新登录,会返回一个bool是否成功
ret = await auth.reauthorize()
if ret: #会返回一个bool是否成功,成功了重新赋值
@@ -1116,15 +1099,20 @@ async def login_reauth(kook_user_id: str):
print(base_print + "reauthorize() Failed! T-T") # 失败打印
# 有保存账户密码+不是邮箱验证用户
if kook_user_id in UserAuthDict['AP'] and (not UserAuthDict[kook_user_id]['2fa']):
- res_auth = await authflow(UserAuthDict['AP'][kook_user_id]['a'], UserAuthDict['AP'][kook_user_id]['p'])
- UserAuthDict[kook_user_id]['auth'] = res_auth # 用账户密码重新登录
- res_auth._cookie_jar.save(f"./log/cookie/{kook_user_id}.cke") #保存cookie
+ auth = EzAuth() # 用账户密码重新登录
+ resw = await auth.authorize(UserAuthDict['AP'][kook_user_id]['a'], UserAuthDict['AP'][kook_user_id]['p'])
+ if not resw['status']: # 需要邮箱验证,那就直接跳出
+ print(base_print + "authorize() need 2fa, return False")
+ return False
+ # 更新auth对象
+ UserAuthDict[kook_user_id]['auth'] = auth
+ auth.save_cookies(f"./log/cookie/{kook_user_id}.cke") # 保存cookie
# 记录使用账户密码重新登录的时间
- UserApLog[kook_user_id][GetTime()] = UserTokenDict[kook_user_id]['GameName']
+ UserPwdReauth[kook_user_id][GetTime()] = UserRiotName[kook_user_id]['GameName']
print(base_print + "authflow() by AP")
ret = True
# 正好返回auth.reauthorize()的bool
- return ret
+ return ret
# 判断是否需要重新获取token
@@ -1139,12 +1127,10 @@ async def check_reauth(def_name: str = "", msg: Union[Message, str] = ''):
try:
user_id = msg if isinstance(msg, str) else msg.author_id #如果是str就直接用
auth = UserAuthDict[user_id]['auth']
- userdict = {
- 'auth_user_id': auth.user_id,
- 'access_token': auth.access_token,
- 'entitlements_token': auth.entitlements_token
- }
- resp = await fetch_valorant_point(userdict)
+ assert isinstance(auth, EzAuth)
+ # 直接从对象中获取user的Token
+ riotUser = auth.get_riotuser_token()
+ resp = await fetch_valorant_point(riotUser)
# resp={'httpStatus': 400, 'errorCode': 'BAD_CLAIMS', 'message': 'Failure validating/decoding RSO Access Token'}
# 如果没有这个键,会直接报错进except; 如果有这个键,就可以继续执行下面的内容
test = resp['httpStatus']
@@ -1189,7 +1175,6 @@ async def check_reauth(def_name: str = "", msg: Union[Message, str] = ''):
return False
-
# 计算当前时间和明天早上8点的差值
def shop_time_remain():
today = datetime.today().strftime("%y-%m-%d %H:%M:%S") #今天日期+时间
@@ -1220,7 +1205,7 @@ def is_CacheLatest(kook_user_id: str):
# 获取每日商店的命令
@bot.command(name='shop', aliases=['SHOP'])
async def get_daily_shop(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
if arg != ():
await msg.reply(f"`/shop`命令不需要参数。您是否想`/login`?")
return
@@ -1233,7 +1218,7 @@ async def get_daily_shop(msg: Message, *arg):
reau = await check_reauth("每日商店", msg)
if reau == False: return #如果为假说明重新登录失败
# 重新获取token成功,从dict中获取玩家id
- player_gamename = f"{UserTokenDict[msg.author_id]['GameName']}#{UserTokenDict[msg.author_id]['TagLine']}"
+ player_gamename = f"{UserRiotName[msg.author_id]['GameName']}#{UserRiotName[msg.author_id]['TagLine']}"
# 获取玩家id成功了,再提示正在获取商店
cm = await get_card("正在尝试获取您的每日商店", "阿狸正在施法,很快就好啦!", icon_cm.duck)
if isinstance(reau, dict): #如果传过来的是一个dict,说明重新登录成功且发送了消息
@@ -1242,15 +1227,13 @@ async def get_daily_shop(msg: Message, *arg):
else:
send_msg = await msg.reply(cm) #记录消息id用于后续更新
- #计算获取每日商店要多久
+ # 计算获取每日商店要多久
start = time.perf_counter() #开始计时
- #从auth的dict中获取对象
+ # 从auth的dict中获取对象
auth = UserAuthDict[msg.author_id]['auth']
- userdict = {
- 'auth_user_id': auth.user_id,
- 'access_token': auth.access_token,
- 'entitlements_token': auth.entitlements_token
- }
+ assert isinstance(auth, EzAuth)
+ riotUser = auth.get_riotuser_token()
+ # 开始判断是否需要获取商店
log_time = ""
a_time = time.time()
global UserShopDict, VipShopBgDict
@@ -1260,62 +1243,76 @@ async def get_daily_shop(msg: Message, *arg):
timeout = shop_time_remain() # 通过当前时间计算商店剩余时间
log_time += f"[Dict_shop] {format(time.time()-a_time,'.4f')} "
else:
- resp = await fetch_daily_shop(userdict) #本地没有,api获取每日商店
+ resp = await fetch_daily_shop(riotUser) #本地没有,api获取每日商店
list_shop = resp["SkinsPanelLayout"]["SingleItemOffers"] # 商店刷出来的4把枪
timeout = resp["SkinsPanelLayout"]["SingleItemOffersRemainingDurationInSeconds"] # 剩余时间
timeout = time.strftime("%H:%M:%S", time.gmtime(timeout)) # 将秒数转为标准时间
# 需要设置uuid来保证是同一个用户,方便同日的下次查询
UserShopDict[msg.author_id] = {}
- UserShopDict[msg.author_id]["auth_user_id"] = UserTokenDict[msg.author_id]["auth_user_id"]
+ UserShopDict[msg.author_id]["auth_user_id"] = UserRiotName[msg.author_id]["auth_user_id"]
UserShopDict[msg.author_id]["SkinsPanelLayout"] = resp["SkinsPanelLayout"]
log_time += f"[Api_shop] {format(time.time()-a_time,'.4f')} "
# 开始画图
draw_time = time.time() #计算画图需要的时间
- is_vip = await vip_ck(msg.author_id) #判断用户是否为VIP
+ is_vip = await BotVip.vip_ck(msg.author_id) #判断用户是否为VIP
img_ret = {'status': True, 'value': None}
upload_flag = True
- # 每天8点bot遍历完之后会把vip的商店结果图存起来
- shop_path = f"./log/img_temp_vip/shop/{msg.author_id}.png"
+ # 初始化为一个展示错误的图片
+ dailyshop_img_src = "https://img.kookapp.cn/assets/2023-02/5UxA8W06B70e803m.png"
# 如果是vip而且path存在,背景图/登录用户没有更改过,图片缓存时间正确
- if is_vip and (os.path.exists(shop_path)) and is_CacheLatest(msg.author_id):
+ if is_vip and is_CacheLatest(msg.author_id):
upload_flag = False #有缓存图,直接使用本地已有链接
dailyshop_img_src = VipShopBgDict['cache'][msg.author_id]['cache_img']
- elif is_vip and (msg.author_id in VipShopBgDict['bg']): #本地缓存路径不存在,或者缓存过期
- play_currency = await fetch_vp_rp_dict(userdict) #获取用户的vp和rp
+ elif is_vip: # 本地缓存路径不存在,或者缓存过期
+ play_currency = await fetch_vp_rp_dict(riotUser) #获取用户的vp和rp
+ # 如果没有设置背景图,那就设置为err
background_img = ('err' if msg.author_id not in VipShopBgDict['bg'] else
VipShopBgDict['bg'][msg.author_id]["background"][0])
- img_ret = await get_shop_img_169(list_shop,
- vp=play_currency['vp'],
- rp=play_currency['rp'],
- bg_img_src=background_img)
- else: # 普通用户/没有自定义图片的vip用户
- img_ret = await get_shop_img_11(list_shop)
-
- if img_ret['status']: #true
+ img_ret = await ShopImg.get_shop_img_169(list_shop,
+ vp=play_currency['vp'],
+ rp=play_currency['rp'],
+ bg_img_src=background_img)
+ else: # 普通用户
+ # 判断是否有缓存命中
+ cache_ret = await ShopRate.query_ShopCache(skinlist=list_shop)
+ if not cache_ret['status']: # 缓存没有命中
+ img_ret = await ShopImg.get_shop_img_11(list_shop)
+ else: # 命中
+ upload_flag = False
+ dailyshop_img_src = cache_ret['img_url']
+ log_time += "[cache] "
+
+ # img_ret 代表是否画图成功,如果是缓存命中,也当成功处理
+ if img_ret['status']:
bg = img_ret['value'] #获取图片
- else: #出现背景图片违规或其他问题
+ else: # 出现背景图片违规或其他问题
await msg.reply(img_ret['value'])
print(f"[GetShopImg] Au:{msg.author_id} {img_ret['value']}")
return
# 获取图片成功,打印画图耗时
- log_time += f"- [Drawing] {format(time.time() - draw_time,'.4f')} - [Au] {msg.author_id}"
- print(log_time)
+ print(log_time + f"- [Drawing] {format(time.time() - draw_time,'.4f')} - [Au] {msg.author_id}")
+ # 判断是否需要上传,false不需要
if upload_flag:
+ # 上传图片
imgByteArr = io.BytesIO()
bg.save(imgByteArr, format='PNG')
- imgByte = imgByteArr.getvalue()
- dailyshop_img_src = await bot_upimg.client.create_asset(imgByte) # 上传图片
- if is_vip: # 如果在bg里面代表有自定义背景图,需更新status
+ imgByte = imgByteArr.getvalue()
+ dailyshop_img_src = await bot_upimg.client.create_asset(imgByte) # type: ignore
+ # 如果在bg里面代表有自定义背景图,需更新status
+ if is_vip:
if msg.author_id in VipShopBgDict['bg']:
VipShopBgDict['bg'][msg.author_id]['status'] = True
# 设置商店图片缓存+图片缓存的时间
VipShopBgDict['cache'][msg.author_id] = {'cache_img': dailyshop_img_src, 'cache_time': time.time()}
+ else: # 非vip,更新缓存
+ await ShopRate.update_ShopCache(skinlist=list_shop, img_url=dailyshop_img_src)
+
# 结束shop的总计时,结果为浮点数,保留两位小数
shop_using_time = format(time.perf_counter() - start, '.2f')
- # 商店的图片
+ # 商店的图片 卡片
cm = CardMessage()
c = Card(color='#fb4b57')
c.append(Module.Header(f"玩家 {player_gamename} 的每日商店!"))
@@ -1323,7 +1320,7 @@ async def get_daily_shop(msg: Message, *arg):
c.append(Module.Container(Element.Image(src=dailyshop_img_src)))
cm.append(c)
- #皮肤评分和评价,用户不在rate_err_user里面才显示(在评论中发表违规言论的用户)
+ # 皮肤评分和评价卡片,用户不在rate_err_user里面才显示(在评论中发表违规言论的用户)
if not check_rate_err_user(msg.author_id):
cm = await ShopRate.get_shop_rate_cm(list_shop, msg.author_id, cm=cm)
end = time.perf_counter() #计算获取评分的时间
@@ -1339,7 +1336,7 @@ async def get_daily_shop(msg: Message, *arg):
return
except requester.HTTPRequester.APIRequestFailed as result: #卡片消息发送失败
- await APIRequestFailed_Handler("shop", traceback.format_exc(), msg, bot, send_msg, cm)
+ await BotLog.APIRequestFailed_Handler("shop", traceback.format_exc(), msg, bot,cm,send_msg=send_msg)
except Exception as result:
err_str = f"ERR! [{GetTime()}] shop\n```\n{traceback.format_exc()}\n```"
if "SkinsPanelLayout" in str(result):
@@ -1348,13 +1345,13 @@ async def get_daily_shop(msg: Message, *arg):
cm = await get_card(f"键值错误,需要重新登录", btext, icon_cm.whats_that)
await upd_card(send_msg['msg_id'], cm, channel_type=msg.channel_type)
else:
- await BaseException_Handler("shop", traceback.format_exc(), msg, bot, send_msg, cm)
+ await BotLog.BaseException_Handler("shop", traceback.format_exc(), msg, send_msg=send_msg)
# 获取夜市
@bot.command(name='night', aliases=['NIGHT'])
async def get_night_market(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
global NightMarketOff
if arg != ():
await msg.reply(f"`/night`命令不需要参数。您是否想`/login`?")
@@ -1383,16 +1380,15 @@ async def get_night_market(msg: Message, *arg):
#计算获取时间
start = time.perf_counter() #开始计时
auth = UserAuthDict[msg.author_id]['auth']
- userdict = {
- 'auth_user_id': auth.user_id,
- 'access_token': auth.access_token,
- 'entitlements_token': auth.entitlements_token
- }
- resp = await fetch_daily_shop(userdict) #获取商店(夜市是相同接口)
+ assert isinstance(auth, EzAuth)
+ riotUser = auth.get_riotuser_token()
+ # 获取商店(夜市是相同接口)
+ resp = await fetch_daily_shop(riotUser)
if "BonusStore" not in resp: # 如果没有这个字段,说明夜市取消了
NightMarketOff = False
- cm1 = await get_card("嗷~ 夜市已关闭 或 Api没能正确返回结果","night_market closed! 'BonusStore' not in resp", icon_cm.duck)
- await upd_card(send_msg['msg_id'], cm1, channel_type=msg.channel_type) # 更新消息
+ cm1 = await get_card("嗷~ 夜市已关闭 或 Api没能正确返回结果", "night_market closed! 'BonusStore' not in resp",
+ icon_cm.duck)
+ await upd_card(send_msg['msg_id'], cm1, channel_type=msg.channel_type) # 更新消息
print("[night_market] night_market closed! 'BonusStore' not in resp")
return
@@ -1403,7 +1399,7 @@ async def get_night_market(msg: Message, *arg):
c = Card(color='#fb4b57')
c.append(
Module.Header(
- f"玩家 {UserTokenDict[msg.author_id]['GameName']}#{UserTokenDict[msg.author_id]['TagLine']} 的夜市!"))
+ f"玩家 {UserRiotName[msg.author_id]['GameName']}#{UserRiotName[msg.author_id]['TagLine']} 的夜市!"))
for Bonus in resp["BonusStore"]["BonusStoreOffers"]:
skin = fetch_skin_bylist(Bonus["Offer"]["OfferID"])
skin_icon = skin["data"]['levels'][0]["displayIcon"]
@@ -1434,15 +1430,15 @@ async def get_night_market(msg: Message, *arg):
return
except requester.HTTPRequester.APIRequestFailed as result: #卡片消息发送失败
- await APIRequestFailed_Handler("night", traceback.format_exc(), msg, bot, send_msg, cm)
+ await BotLog.APIRequestFailed_Handler("night", traceback.format_exc(), msg, bot,cm,send_msg=send_msg)
except Exception as result: # 其他错误
- await BaseException_Handler("night", traceback.format_exc(), msg, bot, send_msg, cm)
+ await BotLog.BaseException_Handler("night", traceback.format_exc(), msg, send_msg=send_msg)
# 设置全局变量,打开/关闭夜市
@bot.command(name='open-nm')
async def open_night_market(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
if msg.author_id == master_id:
global NightMarketOff
@@ -1463,7 +1459,7 @@ async def open_night_market(msg: Message, *arg):
# 获取玩家卡面(添加point的别名)
@bot.command(name='uinfo', aliases=['point', 'UINFO', 'POINT'])
async def get_user_card(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
if arg != ():
await msg.reply(f"`/uinfo`命令不需要参数。您是否想`/login`?")
return
@@ -1484,12 +1480,9 @@ async def get_user_card(msg: Message, *arg):
send_msg = await msg.reply(cm) #记录消息id用于后续更新
auth = UserAuthDict[msg.author_id]['auth']
- userdict = {
- 'auth_user_id': auth.user_id,
- 'access_token': auth.access_token,
- 'entitlements_token': auth.entitlements_token
- }
- resp = await fetch_player_loadout(userdict) #获取玩家装备栏
+ assert isinstance(auth, EzAuth)
+ riotUser = auth.get_riotuser_token()
+ resp = await fetch_player_loadout(riotUser) #获取玩家装备栏
player_card = await fetch_playercard_uuid(resp['Identity']['PlayerCardID']) #玩家卡面id
player_title = await fetch_title_uuid(resp['Identity']['PlayerTitleID']) #玩家称号id
if 'data' not in player_card or player_card['status'] != 200:
@@ -1503,32 +1496,32 @@ async def get_user_card(msg: Message, *arg):
}
print(f"ERR![player_title] Au:{msg.author_id} uuid:{resp['Identity']['PlayerTitleID']}")
# 可能遇到全新账户(没打过游戏)的情况
- if resp['Guns'] == None or resp['Sprays'] == None:
+ if resp['Guns'] == None or resp['Sprays'] == None:
cm = await get_card(f"状态错误!您是否登录了一个全新的账户?", f"card: `{player_card}`\ntitle: `{player_title}`",
icon_cm.whats_that)
await upd_card(send_msg['msg_id'], cm, channel_type=msg.channel_type)
return
# 获取玩家等级
- resp = await fetch_player_level(userdict)
- player_level = resp["Progress"]["Level"] # 玩家等级
- player_level_xp = resp["Progress"]["XP"] # 玩家等级经验值
+ resp = await fetch_player_level(riotUser)
+ player_level = resp["Progress"]["Level"] # 玩家等级
+ player_level_xp = resp["Progress"]["XP"] # 玩家等级经验值
last_fwin = resp["LastTimeGrantedFirstWin"] # 上次首胜时间
- next_fwin = resp["NextTimeFirstWinAvailable"]# 下次首胜重置
+ next_fwin = resp["NextTimeFirstWinAvailable"] # 下次首胜重置
cm = CardMessage()
c = Card(color='#fb4b57')
c.append(
Module.Header(
- f"玩家 {UserTokenDict[msg.author_id]['GameName']}#{UserTokenDict[msg.author_id]['TagLine']} 的个人信息"))
+ f"玩家 {UserRiotName[msg.author_id]['GameName']}#{UserRiotName[msg.author_id]['TagLine']} 的个人信息"))
c.append(Module.Container(Element.Image(src=player_card['data']['wideArt']))) #将图片插入进去
text = f"玩家称号:" + player_title['data']['displayName'] + "\n"
- text+= f"玩家等级:{player_level} - 经验值:{player_level_xp}\n"
- text+= f"上次首胜:{last_fwin}\n"
- text+= f"首胜重置:{next_fwin}"
+ text += f"玩家等级:{player_level} - 经验值:{player_level_xp}\n"
+ text += f"上次首胜:{last_fwin}\n"
+ text += f"首胜重置:{next_fwin}"
c.append(Module.Section(Element.Text(text, Types.Text.KMD)))
#获取玩家的vp和r点剩余的text
- resp = await fetch_vp_rp_dict(userdict)
+ resp = await fetch_vp_rp_dict(riotUser)
text = f"(emj)r点(emj)[3986996654014459/X3cT7QzNsu03k03k] RP {resp['rp']} "
text += f"(emj)vp(emj)[3986996654014459/qGVLdavCfo03k03k] VP {resp['vp']}\n"
c.append(Module.Section(Element.Text(text, Types.Text.KMD)))
@@ -1542,7 +1535,7 @@ async def get_user_card(msg: Message, *arg):
return
except requester.HTTPRequester.APIRequestFailed as result: #卡片消息发送失败
- await APIRequestFailed_Handler("uinfo", traceback.format_exc(), msg, bot, send_msg, cm)
+ await BotLog.APIRequestFailed_Handler("uinfo", traceback.format_exc(), msg, bot, cm,send_msg=send_msg)
except Exception as result:
err_str = f"ERR! [{GetTime()}] uinfo\n```\n{traceback.format_exc()}\n```"
if "Identity" in str(result) or "Balances" in str(result):
@@ -1550,13 +1543,13 @@ async def get_user_card(msg: Message, *arg):
cm2 = await get_card(f"键值错误,需要重新登录", f"KeyError:{result}, please re-login", icon_cm.lagging)
await upd_card(send_msg['msg_id'], cm2, channel_type=msg.channel_type)
else:
- await BaseException_Handler("uinfo", traceback.format_exc(), msg, bot, send_msg, cm)
+ await BotLog.BaseException_Handler("uinfo", traceback.format_exc(), msg, send_msg=send_msg)
# 获取捆绑包信息(无需登录)
@bot.command(name='bundle', aliases=['skin'])
async def get_bundle(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
if arg == ():
await msg.reply(f"函数参数错误,name: `{arg}`\n")
return
@@ -1599,7 +1592,6 @@ async def get_bundle(msg: Message, *arg):
await bot.client.send(debug_ch, err_str)
-
# 设置rate的错误用户
@bot.command(name='ban-r')
async def set_rate_err_user(msg: Message, user_id: str):
@@ -1612,7 +1604,7 @@ async def set_rate_err_user(msg: Message, user_id: str):
elif user_id in SkinRateDict['data']:
for skin, info in SkinRateDict['data'][user_id].items():
# 找到这条评论,将其删除
- if not await ShopRate.remove_UserRate(skin,user_id):
+ if not await ShopRate.remove_UserRate(skin, user_id):
await msg.reply(f"Au:{user_id} 删除 {skin} [{info['name']}] 错误")
# 删除完该用户的所有评论之后,将其放入err_user
@@ -1636,7 +1628,7 @@ async def clear_rate_err_user():
# 给一个皮肤评分(灵感来自微信小程序”瓦的小卖铺“)
@bot.command(name="rate", aliases=['评分'])
async def rate_skin_add(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
if check_rate_err_user(msg.author_id):
await msg.reply(f"您有过不良评论记录,阿狸现已不允许您使用相关功能\n后台存放了所有用户的评论内容和评论时间。在此提醒,请不要在评论的时候发送不雅言论!")
return
@@ -1653,7 +1645,7 @@ async def rate_skin_add(msg: Message, *arg):
# 将皮肤list插入到选择列表中,用户使用/rts命令选择
UserRtsDict[msg.author_id] = retlist
# 获取选择列表的text
- ret = await ShopRate.get_skinlist_rate_text(retlist,msg.author_id)
+ ret = await ShopRate.get_skinlist_rate_text(retlist, msg.author_id)
text = f"```\n{ret['text']}```"
cm = CardMessage()
@@ -1670,15 +1662,15 @@ async def rate_skin_add(msg: Message, *arg):
await msg.reply(cm)
except requester.HTTPRequester.APIRequestFailed as result: #卡片消息发送失败
- await APIRequestFailed_Handler("rate", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.APIRequestFailed_Handler("rate", traceback.format_exc(), msg, bot,cm)
except Exception as result: # 其他错误
- await BaseException_Handler("rate", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.BaseException_Handler("rate", traceback.format_exc(), msg)
#选择皮肤(这个命令必须跟着上面的命令用)
@bot.command(name="rts")
async def rate_skin_select(msg: Message, index: str = "err", rating: str = "err", *arg):
- logging(msg)
+ BotLog.logging(msg)
if check_rate_err_user(msg.author_id):
await msg.reply(f"您有过不良评论记录,阿狸现已不允许您使用相关功能\n后台存放了所有用户的评论内容和评论时间。在此提醒,请不要在评论的时候发送不雅言论!")
return
@@ -1705,12 +1697,12 @@ async def rate_skin_select(msg: Message, index: str = "err", rating: str = "err"
S_skin = UserRtsDict[msg.author_id][_index]
skin_uuid = S_skin['skin']['lv_uuid']
comment = " ".join(arg) #用户对此皮肤的评论
- point = _rating # 初始化分数
+ point = _rating # 初始化分数
text1 = ""
text2 = ""
# 先从leancloud获取该皮肤的分数
skin_rate = await ShopRate.query_SkinRate(skin_uuid)
- if skin_rate['status']: # 找到了
+ if skin_rate['status']: # 找到了
#用户的评分和皮肤平均分差值不能超过32,避免有人乱刷分
if abs(float(_rating) - skin_rate['rating']) <= 32:
# 计算分数
@@ -1718,9 +1710,9 @@ async def rate_skin_select(msg: Message, index: str = "err", rating: str = "err"
else: # 差值过大,不计入皮肤平均值
point = skin_rate['rating']
text2 += f"由于您的评分和皮肤平均分差值大于32,所以您的评分不会计入皮肤平均分,但您的评论会进行保留\n"
-
+
# 更新数据库中皮肤评分
- await ShopRate.update_SkinRate(skin_uuid,S_skin['skin']['displayName'],point)
+ await ShopRate.update_SkinRate(skin_uuid, S_skin['skin']['displayName'], point)
# 用户之前没有评价过,新建键值
if msg.author_id not in SkinRateDict['data']:
SkinRateDict['data'][msg.author_id] = {}
@@ -1729,12 +1721,12 @@ async def rate_skin_select(msg: Message, index: str = "err", rating: str = "err"
SkinRateDict['data'][msg.author_id][skin_uuid]['name'] = S_skin['skin']['displayName']
SkinRateDict['data'][msg.author_id][skin_uuid]['cmt'] = comment
SkinRateDict['data'][msg.author_id][skin_uuid]['pit'] = point
- SkinRateDict['data'][msg.author_id][skin_uuid]['time'] = int(time.time()) # 秒级
+ SkinRateDict['data'][msg.author_id][skin_uuid]['time'] = int(time.time()) # 秒级
SkinRateDict['data'][msg.author_id][skin_uuid]['msg_id'] = msg.id
# 数据库添加该评论
- await ShopRate.update_UserRate(skin_uuid,SkinRateDict['data'][msg.author_id][skin_uuid],msg.author_id)
+ await ShopRate.update_UserRate(skin_uuid, SkinRateDict['data'][msg.author_id][skin_uuid], msg.author_id)
# 更新用户已评价的皮肤
- await ShopRate.update_UserCmt(msg.author_id,skin_uuid)
+ await ShopRate.update_UserCmt(msg.author_id, skin_uuid)
text1 += f"评价成功!{S_skin['skin']['displayName']}"
text2 += f"您的评分:{_rating}\n"
@@ -1750,15 +1742,15 @@ async def rate_skin_select(msg: Message, index: str = "err", rating: str = "err"
await msg.reply(f"您需要执行 `/rate 皮肤名` 来查找皮肤\n再使用 `/rts` 进行选择")
except requester.HTTPRequester.APIRequestFailed as result: #卡片消息发送失败
- await APIRequestFailed_Handler("rts", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.APIRequestFailed_Handler("rts", traceback.format_exc(), msg, bot, cm)
except Exception as result: # 其他错误
- await BaseException_Handler("rts", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.BaseException_Handler("rts", traceback.format_exc(), msg)
# 查看昨日牛人/屌丝
@bot.command(name="kkn")
-async def rate_skin_select(msg: Message):
- logging(msg)
+async def show_shoprate(msg: Message):
+ BotLog.logging(msg)
if check_rate_err_user(msg.author_id):
await msg.reply(f"您有过不良评论记录,阿狸现已不允许您使用相关功能\n后台存放了所有用户的评论内容和评论时间。在此提醒,请不要在评论的时候发送不雅言论!")
return
@@ -1768,7 +1760,7 @@ async def rate_skin_select(msg: Message):
if not cmpRet['status']:
await msg.reply(f"获取昨日天选之子和丐帮帮主出错!请重试或联系开发者")
return
-
+
cm = CardMessage()
c = Card(Module.Header(f"来看看昨日天选之子和丐帮帮主吧!"), Module.Divider())
# best
@@ -1799,10 +1791,9 @@ async def rate_skin_select(msg: Message):
print(f"[{GetTime()}] [kkn] reply success")
except requester.HTTPRequester.APIRequestFailed as result: #卡片消息发送失败
- await APIRequestFailed_Handler("rts", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.APIRequestFailed_Handler("rts", traceback.format_exc(), msg, bot, cm)
except Exception as result: # 其他错误
- await BaseException_Handler("rts", traceback.format_exc(), msg, bot, None, cm)
-
+ await BotLog.BaseException_Handler("rts", traceback.format_exc(), msg)
# 检查用户是否在错误用户里面
@@ -1836,7 +1827,7 @@ async def check_notify_err_user(msg: Message):
#设置提醒(出现xx皮肤)
@bot.command(name="notify-add", aliases=['notify-a'])
async def add_skin_notify(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
if arg == ():
await msg.reply(f"你没有提供皮肤参数!skin: `{arg}`")
return
@@ -1844,7 +1835,7 @@ async def add_skin_notify(msg: Message, *arg):
if await check_notify_err_user(msg):
return
# 检查用户的提醒栏位
- vip_status = await vip_ck(msg.author_id)
+ vip_status = await BotVip.vip_ck(msg.author_id)
if msg.author_id in SkinNotifyDict['data'] and not vip_status:
if len(SkinNotifyDict['data'][msg.author_id]) > NOTIFY_NUM:
cm = await get_card(f"您的皮肤提醒栏位已满", f"想解锁更多栏位,可以来[支持一下](https://afdian.net/a/128ahri?tab=shop)阿狸呢!",
@@ -1892,13 +1883,13 @@ async def add_skin_notify(msg: Message, *arg):
await msg.reply(cm)
except Exception as result: # 其他错误
- await BaseException_Handler("notify-add", traceback.format_exc(), msg, bot, None, cm)
+ await BotLog.BaseException_Handler("notify-add", traceback.format_exc(), msg)
#选择皮肤(这个命令必须跟着上面的命令用)
@bot.command(name="sts")
async def select_skin_notify(msg: Message, n: str = "err", *arg):
- logging(msg)
+ BotLog.logging(msg)
if n == "err" or '-' in n:
await msg.reply(f"参数不正确!请选择您需要提醒的皮肤序号")
return
@@ -1932,17 +1923,17 @@ async def select_skin_notify(msg: Message, n: str = "err", *arg):
except requester.HTTPRequester.APIRequestFailed as result: #消息发送失败
err_str = f"ERR! [{GetTime()}] sts\n```\n{traceback.format_exc()}\n```\n"
await bot.client.send(debug_ch, err_str)
- await APIRequestFailed_Handler("sts", traceback.format_exc(), msg, bot, None)
+ await BotLog.APIRequestFailed_Handler("sts", traceback.format_exc(), msg, bot)
except Exception as result: # 其他错误
err_str = f"ERR! [{GetTime()}] sts\n```\n{traceback.format_exc()}\n```\n"
await bot.client.send(debug_ch, err_str)
- await BaseException_Handler("sts", traceback.format_exc(), msg, bot, None)
+ await BotLog.BaseException_Handler("sts", traceback.format_exc(), msg)
# 显示当前设置好了的皮肤通知
@bot.command(name="notify-list", aliases=['notify-l'])
async def list_skin_notify(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
if await check_notify_err_user(msg):
return
@@ -1958,13 +1949,13 @@ async def list_skin_notify(msg: Message, *arg):
except Exception as result:
err_str = f"ERR! [{GetTime()}] notify-list\n```\n{traceback.format_exc()}\n```"
await bot.client.send(debug_ch, err_str)
- await BaseException_Handler("notify-list", traceback.format_exc(), msg, bot, None)
+ await BotLog.BaseException_Handler("notify-list", traceback.format_exc(), msg)
# 删除已有皮肤通知
@bot.command(name="notify-del", aliases=['notify-d'])
async def delete_skin_notify(msg: Message, uuid: str = "err", *arg):
- logging(msg)
+ BotLog.logging(msg)
if uuid == 'err':
await msg.reply(f"请提供正确的皮肤uuid:`{uuid}`")
return
@@ -1983,7 +1974,7 @@ async def delete_skin_notify(msg: Message, uuid: str = "err", *arg):
except Exception as result:
err_str = f"ERR! [{GetTime()}] notify-del\n```\n{traceback.format_exc()}\n```"
await bot.client.send(debug_ch, err_str)
- await BaseException_Handler("notify-del", traceback.format_exc(), msg, bot, None)
+ await BotLog.BaseException_Handler("notify-del", traceback.format_exc(), msg)
#独立函数,为了封装成命令+定时
@@ -1994,15 +1985,16 @@ async def auto_skin_notify():
UserShopDict = {} #清空用户的商店
#清空昨日最好/最差用户的皮肤表
SkinRateDict["kkn"] = copy.deepcopy(SkinRateDict["cmp"])
- SkinRateDict["cmp"]["best"]["skin"] = list()
- SkinRateDict["cmp"]["best"]["pit"] = 0
- SkinRateDict["cmp"]["worse"]["skin"] = list()
- SkinRateDict["cmp"]["worse"]["pit"] = 100
- await ShopRate.update_ShopCmp() # 更新数据库中的记录
- print("[BOT.TASK.NOTIFY] SkinRateDict/UserShopDict clear, sleep(10)")
+ SkinRateDict["cmp"]["best"]["list_shop"] = list()
+ SkinRateDict["cmp"]["best"]["rating"] = 0
+ SkinRateDict["cmp"]["worse"]["list_shop"] = list()
+ SkinRateDict["cmp"]["worse"]["rating"] = 100
+ # 更新数据库中的记录,并重置计数器
+ await ShopRate.update_ShopCmp(SkinRateDict["kkn"]["best"], SkinRateDict["kkn"]["worse"], 'kook', True)
+ print(f"[BOT.TASK.NOTIFY] SkinRateDict/UserShopDict clear, sleep(10) [{GetTime()}]")
#睡10s再开始遍历(避免时间不准)
await asyncio.sleep(10)
- print("[BOT.TASK.NOTIFY] auto_skin_notify Start")
+ print(f"[BOT.TASK.NOTIFY] skin_notify Start [{GetTime()}]")
#加载vip用户列表
VipUserD = copy.deepcopy(VipUserDict)
err_count = 0 # 设置一个count来计算出错的用户数量
@@ -2017,13 +2009,10 @@ async def auto_skin_notify():
shop_text = "err"
start = time.perf_counter() #开始计时
auth = UserAuthDict[vip]['auth']
- userdict = {
- 'auth_user_id': auth.user_id,
- 'access_token': auth.access_token,
- 'entitlements_token': auth.entitlements_token
- }
+ assert isinstance(auth, EzAuth)
+ riotUser = auth.get_riotuser_token()
a_time = time.time() # 获取token的时间
- resp = await fetch_daily_shop(userdict) # 获取每日商店
+ resp = await fetch_daily_shop(riotUser) # 获取每日商店
# 判断夜市有没有开,只会判断一次
global NightMarketOff #true代表夜市没有开启
@@ -2037,19 +2026,19 @@ async def auto_skin_notify():
await ShopRate.check_shop_rate(vip, list_shop) #计算用户商店得分
#vip用户会提前缓存当日商店,需要设置uuid来保证是同一个游戏用户
UserShopDict[vip] = {}
- UserShopDict[vip]["auth_user_id"] = UserTokenDict[vip]["auth_user_id"]
+ UserShopDict[vip]["auth_user_id"] = UserRiotName[vip]["auth_user_id"]
UserShopDict[vip]["SkinsPanelLayout"] = resp["SkinsPanelLayout"]
#直接获取商店图片
draw_time = time.time() #开始计算画图需要的时间
img_shop_path = f"./log/img_temp_vip/shop/{vip}.png"
- play_currency = await fetch_vp_rp_dict(userdict) #获取用户的vp和rp
+ play_currency = await fetch_vp_rp_dict(riotUser) #获取用户的vp和rp
# 设置用户背景图,如果在则用,否则返回err
background_img = ('err' if vip not in VipShopBgDict['bg'] else
VipShopBgDict['bg'][vip]["background"][0])
- img_ret = await get_shop_img_169(list_shop,
- vp=play_currency['vp'],
- rp=play_currency['rp'],
- bg_img_src=background_img)
+ img_ret = await ShopImg.get_shop_img_169(list_shop,
+ vp=play_currency['vp'],
+ rp=play_currency['rp'],
+ bg_img_src=background_img)
if img_ret['status']:
bg_shop = img_ret['value']
bg_shop.save(img_shop_path, format='PNG')
@@ -2079,14 +2068,14 @@ async def auto_skin_notify():
if shop_text == "err":
c.append(
Module.Header(
- f"早安!玩家 {UserTokenDict[vip]['GameName']}#{UserTokenDict[vip]['TagLine']} 的每日商店"))
+ f"早安!玩家 {UserRiotName[vip]['GameName']}#{UserRiotName[vip]['TagLine']} 的每日商店"))
c.append(Module.Context(f"失效时间剩余: {timeout} 本次查询用时: {using_time}s"))
c.append(Module.Container(Element.Image(src=dailyshop_img_src)))
else:
c.append(
Module.Section(
Element.Text(
- f"早安!玩家 {UserTokenDict[vip]['GameName']}#{UserTokenDict[vip]['TagLine']}",
+ f"早安!玩家 {UserRiotName[vip]['GameName']}#{UserRiotName[vip]['TagLine']}",
Types.Text.KMD), Element.Image(src=icon_cm.shot_on_fire, size='sm')))
c.append(Module.Section(Element.Text(shop_text, Types.Text.KMD)))
c.append(Module.Context(Element.Text(f"这里有没有你想要的枪皮呢?", Types.Text.KMD)))
@@ -2122,16 +2111,13 @@ async def auto_skin_notify():
if aid in UserAuthDict:
if await check_reauth("定时获取玩家商店", aid) == True: # 重新登录,如果为假说明重新登录失败
auth = UserAuthDict[aid]['auth']
- userdict = {
- 'auth_user_id': auth.user_id,
- 'access_token': auth.access_token,
- 'entitlements_token': auth.entitlements_token
- }
+ assert isinstance(auth, EzAuth)
+ riotUser = auth.get_riotuser_token()
#vip用户在前面已经获取过商店了
- if await vip_ck(aid):
+ if await BotVip.vip_ck(aid):
list_shop = UserShopDict[aid]["SkinsPanelLayout"]["SingleItemOffers"]
else:
- resp = await fetch_daily_shop(userdict) # 获取每日商店
+ resp = await fetch_daily_shop(riotUser) # 获取每日商店
list_shop = resp["SkinsPanelLayout"]["SingleItemOffers"] # 商店刷出来的4把枪
await ShopRate.check_shop_rate(vip, list_shop) #计算非vip用户商店得分
@@ -2181,37 +2167,37 @@ async def auto_skin_notify():
async def auto_skin_notify_task():
await auto_skin_notify()
+
# 手动执行notify task
@bot.command(name='notify-test')
async def auto_skin_notify_cmd(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
if msg.author_id == master_id:
await auto_skin_notify()
+
# 手动更新商店物品和价格
@bot.command(name='update_spb', aliases=['update', 'upd'])
async def update_skin_price_bundle(msg: Message):
- logging(msg)
+ BotLog.logging(msg)
try:
if msg.author_id == master_id:
- if await update_skins(msg):
+ if await ValFileUpd.update_skins(msg):
await msg.reply(f"成功更新:商店皮肤")
- if await update_bundle_url(msg, bot_upimg):
+ if await ValFileUpd.update_bundle_url(msg, bot_upimg):
await msg.reply(f"成功更新:捆绑包")
# 获取物品价格需要登录
auth = UserAuthDict[msg.author_id]['auth']
- userdict = {
- 'auth_user_id': auth.user_id,
- 'access_token': auth.access_token,
- 'entitlements_token': auth.entitlements_token
- }
- if await update_price(msg, userdict):
+ assert isinstance(auth, EzAuth)
+ riotUser = auth.get_riotuser_token()
+ if await ValFileUpd.update_price(msg, riotUser):
await msg.reply(f"成功更新:物品价格")
except Exception as result:
err_str = f"ERR! [{GetTime()}] update_spb\n```\n{traceback.format_exc()}\n```"
print(err_str)
await msg.reply(err_str)
+
#######################################################################################################
#######################################################################################################
@@ -2219,11 +2205,11 @@ async def update_skin_price_bundle(msg: Message):
# 显示当前阿狸加入了多少个服务器,以及用户数量
@bot.command(name='log-list', aliases=['log-l', 'log'])
async def bot_log_list(msg: Message, *arg):
- logging(msg)
+ BotLog.logging(msg)
try:
if msg.author_id == master_id:
- retDict = await log_bot_list(msg) # 获取用户/服务器列表
- res_text = await log_bot_list_text(retDict) # 获取text
+ retDict = await BotLog.log_bot_list(msg) # 获取用户/服务器列表
+ res_text = await BotLog.log_bot_list_text(retDict) # 获取text
cm = CardMessage()
c = Card(
@@ -2246,21 +2232,23 @@ async def bot_log_list(msg: Message, *arg):
await msg.reply(f"{err_str}")
print(err_str)
+
@bot.command(name='mem')
-async def proc_check(msg:Message,*arg):
- logging(msg)
+async def proc_check(msg: Message, *arg):
+ BotLog.logging(msg)
try:
if msg.author_id == master_id:
- cm = await get_proc_info()
+ cm = await BotLog.get_proc_info()
await msg.reply(cm)
except:
err_str = f"ERR! [{GetTime()}] mem\n```\n{traceback.format_exc()}\n```"
await msg.reply(f"{err_str}")
print(err_str)
+
#在阿狸开机的时候自动加载所有保存过的cookie
-@bot.task.add_date()
-async def loading_channel_cookie():
+@bot.on_startup
+async def loading_cache(bot:Bot):
try:
global debug_ch, cm_send_test
cm_send_test = await bot_upimg.client.fetch_public_channel(config['channel']["img_upload_ch"])
@@ -2280,33 +2268,53 @@ async def loading_channel_cookie():
log_str_success = "[BOT.TASK] load cookie success = Au:"
log_str_failed = "[BOT.TASK] load cookie failed! = Au:"
log_not_exits = "[BOT.TASK] cookie path not exists = Au:"
- #遍历用户列表
+ # 遍历用户列表
for user, uinfo in VipUserDict.items():
cookie_path = f"./log/cookie/{user}.cke"
#如果路径存在,那么说明已经保存了这个vip用户的cookie
if os.path.exists(cookie_path):
- auth = RiotAuth() #新建一个对象
- auth._cookie_jar.load(cookie_path) #加载cookie
+ auth = EzAuth()
+ auth.load_cookies(cookie_path) #加载cookie
+ ret_bool = await auth.reauthorize() #尝试登录
+ if ret_bool: # True登陆成功
+ UserAuthDict[user] = {"auth": auth, "2fa": False} #将对象插入
+ log_str_success += f"({user})"
+ else:
+ del auth # 删除对象
+ log_str_failed += f"({user}) "
+ continue
+ else:
+ log_not_exits += f"({user}) "
+ continue
+ # 结束任务
+ print(log_str_success + "\n" + log_str_failed + "\n" + log_not_exits)
+ print(f"[BOT.TASK] loading user cookie finished {GetTime()}")
+
+ # api缓存的用户列表
+ log_str_success = "[BOT.TASK] api load cookie success = Au:"
+ log_str_failed = "[BOT.TASK] api load cookie failed! = Au:"
+ log_not_exits = "[BOT.TASK] api cookie path not exists = Au:"
+ # 遍历api用户列表
+ for user in ApiAuthLog:
+ cookie_path = f"./log/cookie/api/{user}.cke"
+ #如果路径存在,那么说明已经保存了这个vip用户的cookie
+ if os.path.exists(cookie_path):
+ auth = EzAuth()
+ auth.load_cookies(cookie_path) #加载cookie
ret_bool = await auth.reauthorize() #尝试登录
if ret_bool: # True登陆成功
UserAuthDict[user] = {"auth": auth, "2fa": False} #将对象插入
log_str_success += f"({user})"
- #print(f"[BOT.TASK] Au:{user} - load cookie success!")
- #不用重新修改UserTokenDict里面的游戏名和uuid
- #因为UserTokenDict是在login的时候保存的,只要用户没有切换账户
- #那么玩家id和uuid都是不会变化的,也没必要重新加载
else:
+ del auth # 删除对象
log_str_failed += f"({user}) "
- #print(f"[BOT.TASK] Au:{user} - load cookie failed!")
continue
else:
log_not_exits += f"({user}) "
continue
- #结束任务
- print(log_str_success) #打印正常的用户
- print(log_str_failed) #打印失败的用户
- print(log_not_exits) #打印路径不存在的用户
- print("[BOT.TASK] loading cookie finished")
+ # 结束任务
+ print(log_str_success + "\n" + log_str_failed + "\n" + log_not_exits)
+ print(f"[BOT.TASK] loading api user cookie finished {GetTime()}")
# 开机 (如果是主文件就开机)
diff --git a/code/utils/BotLog.py b/code/utils/BotLog.py
index cfd4329..cd93efe 100644
--- a/code/utils/BotLog.py
+++ b/code/utils/BotLog.py
@@ -1,16 +1,14 @@
import json
-import copy
import traceback
+from copy import deepcopy
from khl import Message, PrivateMessage, Bot
-from khl.card import Card, CardMessage, Element, Module, Types, Struct
-from utils.KookApi import guild_list, guild_view, upd_card, get_card, icon_cm
+from khl.card import Card, CardMessage, Element, Module, Types
from PIL import Image, ImageDraw, ImageFont
-from copy import deepcopy
-
-from utils.Gtime import GetTime
# 用户数量的记录文件
-from utils.FileManage import BotUserDict
+from .FileManage import bot,BotUserDict, FileManage
+from .Gtime import GetTime
+from .KookApi import guild_list, guild_view, upd_card, get_card, icon_cm
# 记录私聊的用户信息
@@ -25,9 +23,8 @@ def log_bot_user(user_id: str):
# 记录服务器中的用户信息
-def log_bot_guild(user_id: str, guild_id: str, time):
+def log_bot_guild(user_id: str, guild_id: str, time) -> str:
global BotUserDict
- # BotUserDict['cmd_total']+=1
log_bot_user(user_id)
# 服务器不存在,新的用户服务器
if guild_id not in BotUserDict['guild']['data']:
@@ -46,7 +43,7 @@ def log_bot_guild(user_id: str, guild_id: str, time):
# 在控制台打印msg内容,用作日志
-def logging(msg: Message):
+def logging(msg: Message) -> None:
try:
now_time = GetTime()
if isinstance(msg, PrivateMessage):
@@ -70,7 +67,7 @@ def logging(msg: Message):
# 画图,把当前加入的服务器总数等等信息以图片形式显示在README中
-async def log_bot_img():
+async def log_bot_img() -> None:
bg = deepcopy(log_base_img) # 新建一个画布
draw = ImageDraw.Draw(bg) # 让bg这个图层能被写字
# 第一个参数 standard_text_position 是固定参数坐标 , 第二个是文字内容 , 第三个是字体 , 第四个是字体颜色
@@ -91,43 +88,38 @@ async def log_bot_img():
# bot用户记录dict处理
-async def log_bot_list(msg: Message):
+async def log_bot_list(msg: Message) -> FileManage:
global BotUserDict
- try:
- # 加入的服务器数量,api获取
- Glist = await guild_list()
- Glist = Glist['data']['meta']['total']
- # api正常返回结果,赋值给全局变量
- BotUserDict['guild']['guild_total'] = Glist
- # dict里面保存的服务器,有用户活跃的服务器数量
- BotUserDict['guild']['guild_active'] = len(BotUserDict['guild']['data'])
- # 计算用户总数
- BotUserDict['user']['user_total'] = len(BotUserDict['user']['data'])
- # 遍历列表,获取服务器名称
- tempDict = copy.deepcopy(BotUserDict)
- for gu in tempDict['guild']['data']:
- if 'name' not in tempDict['guild']['data'][gu]:
- Gret = await guild_view(gu)
- if Gret['code'] !=0: # 没有正常返回,可能是服务器被删除
- del BotUserDict['guild']['data'][gu] # 删除键值
- print(f"[log_bot_list] G:{gu} guild-view {Gret}")
- continue
- # 正常返回,赋值
- BotUserDict['guild']['data'][gu]['name'] = Gret['data']['name']
- else:
+ # 加入的服务器数量,api获取
+ Glist = await guild_list()
+ Glist = Glist['data']['meta']['total']
+ # api正常返回结果,赋值给全局变量
+ BotUserDict['guild']['guild_total'] = Glist
+ # dict里面保存的服务器,有用户活跃的服务器数量
+ BotUserDict['guild']['guild_active'] = len(BotUserDict['guild']['data'])
+ # 计算用户总数
+ BotUserDict['user']['user_total'] = len(BotUserDict['user']['data'])
+ # 遍历列表,获取服务器名称
+ tempDict = deepcopy(BotUserDict)
+ for gu in tempDict['guild']['data']:
+ if 'name' not in tempDict['guild']['data'][gu]:
+ Gret = await guild_view(gu)
+ if Gret['code'] != 0: # 没有正常返回,可能是服务器被删除
+ del BotUserDict['guild']['data'][gu] # 删除键值
+ print(f"[log_bot_list] G:{gu} guild-view {Gret}")
continue
- # 保存图片和文件
- await log_bot_img()
- print("[log_bot_list] file handling finish, return BotUserDict")
- return BotUserDict
- except:
- err_str = f"ERR! [{GetTime()}] log-list\n```\n{traceback.format_exc()}\n```"
- await msg.reply(f"{err_str}")
- print(err_str)
+ # 正常返回,赋值
+ BotUserDict['guild']['data'][gu]['name'] = Gret['data']['name']
+ else:
+ continue
+ # 保存图片和文件
+ await log_bot_img()
+ print("[log_bot_list] file handling finish, return BotUserDict")
+ return BotUserDict
# 通过log_bot_list分选出两列服务器名和服务器用户数
-async def log_bot_list_text(logDict: dict):
+async def log_bot_list_text(logDict: dict) -> dict[str, str]:
i = 1
text_name = "No 服务器名\n"
text_user = "用户数\n"
@@ -146,7 +138,20 @@ async def log_bot_list_text(logDict: dict):
# 出现kook api异常的通用处理
-async def APIRequestFailed_Handler(def_name: str, excp, msg: Message, bot: Bot, send_msg=None, cm: CardMessage = None):
+async def APIRequestFailed_Handler(def_name: str,
+ excp: str,
+ msg: Message,
+ bot: Bot,
+ cm: CardMessage = None,
+ send_msg: dict[str, str] = {}) -> None:
+ """Args:
+ - def_name: name of def to print in log
+ - excp: taraceback.fromat_exc()
+ - msg: khl.Message
+ - bot: khl.Bot
+ - cm: khl.card.CardMessage, for json.dumps / resend
+ - send_msg: return value of msg.reply or bot.send
+ """
err_str = f"ERR! [{GetTime()}] {def_name} Au:{msg.author_id} APIRequestFailed\n{excp}"
print(err_str)
text = f"啊哦,出现了一些问题"
@@ -168,7 +173,7 @@ async def APIRequestFailed_Handler(def_name: str, excp, msg: Message, bot: Bot,
text_sub = f"阿狸无法向您发出私信,请检查你的隐私设置"
cm0 = await get_card(text, text_sub, icon_cm.lagging)
- if send_msg != None: # 非none则执行更新消息,而不是直接发送
+ if send_msg: # 非none则执行更新消息,而不是直接发送
await upd_card(send_msg['msg_id'], cm0, channel_type=msg.channel_type)
else:
await msg.reply(cm0)
@@ -176,12 +181,19 @@ async def APIRequestFailed_Handler(def_name: str, excp, msg: Message, bot: Bot,
# 基础错误的处理,带login提示(部分命令不需要这个提示)
async def BaseException_Handler(def_name: str,
- excp,
+ excp: str,
msg: Message,
- bot: Bot,
- send_msg=None,
- cm: CardMessage = None,
- help="您可能需要重新执行/login操作"):
+ send_msg: dict[str, str] = {},
+ debug_send = None,
+ help="建议加入帮助频道找我康康到底是啥问题") -> None: # type: ignore
+ """Args:
+ - def_name: name of def to print in log
+ - excp: taraceback.fromat_exc()
+ - msg: khl.Message
+ - send_msg: return value of msg.reply or bot.send
+ - debug_send: Channel obj for sending err_str, send if not None
+ - help: str for help_info, replyed in msg.reply
+ """
err_str = f"ERR! [{GetTime()}] {def_name} Au:{msg.author_id}\n```\n{excp}\n```"
print(err_str)
cm0 = CardMessage()
@@ -192,28 +204,30 @@ async def BaseException_Handler(def_name: str,
c.append(Module.Divider())
c.append(Module.Section('有任何问题,请加入帮助服务器与我联系', Element.Button('帮助', 'https://kook.top/gpbTwZ', Types.Click.LINK)))
cm0.append(c)
- if send_msg != None: # 非none则执行更新消息,而不是直接发送
+ if send_msg: # 非{}则执行更新消息,而不是直接发送
await upd_card(send_msg['msg_id'], cm0, channel_type=msg.channel_type)
else:
await msg.reply(cm0)
+ # 如果debug_send不是None,则发送信息到报错频道
+ if debug_send:
+ await bot.client.send(debug_send, err_str)
#############################################################################################
-import psutil,os
+import psutil, os
+
+
# 获取进程信息
-async def get_proc_info():
+async def get_proc_info() -> CardMessage:
p = psutil.Process(os.getpid())
- text =f"霸占的CPU百分比:{p.cpu_percent()} %\n"
- text+=f"占用的MEM百分比:{format(p.memory_percent(), '.3f')} %\n"
- text+=f"吃下的物理内存:{format((p.memory_info().rss / 1024 / 1024), '.4f')} MB\n"
- text+=f"开辟的虚拟内存:{format((p.memory_info().vms / 1024 / 1024), '.4f')} MB\n"
- text+=f"IO信息:\n{p.io_counters()}"
+ text = f"霸占的CPU百分比:{p.cpu_percent()} %\n"
+ text += f"占用的MEM百分比:{format(p.memory_percent(), '.3f')} %\n"
+ text += f"吃下的物理内存:{format((p.memory_info().rss / 1024 / 1024), '.4f')} MB\n"
+ text += f"开辟的虚拟内存:{format((p.memory_info().vms / 1024 / 1024), '.4f')} MB\n"
+ text += f"IO信息:\n{p.io_counters()}"
cm = CardMessage()
- c = Card(
- Module.Header(f"来看看阿狸当前的负载吧!"),
- Module.Context(f"记录于 {GetTime()}"),Module.Divider(),
- Module.Section(Element.Text(text,Types.Text.KMD))
- )
+ c = Card(Module.Header(f"来看看阿狸当前的负载吧!"), Module.Context(f"记录于 {GetTime()}"), Module.Divider(),
+ Module.Section(Element.Text(text, Types.Text.KMD)))
cm.append(c)
return cm
\ No newline at end of file
diff --git a/code/utils/BotVip.py b/code/utils/BotVip.py
index 540eab9..90cf888 100644
--- a/code/utils/BotVip.py
+++ b/code/utils/BotVip.py
@@ -7,10 +7,10 @@
from khl import Message, Bot, Channel
from khl.card import Card, CardMessage, Element, Module, Types
from datetime import datetime, timedelta
-from utils.KookApi import icon_cm,bot
-from utils.Gtime import GetTime
-from utils.FileManage import VipShopBgDict,config
-from utils.ShopImg import img_requestor
+from .KookApi import icon_cm
+from .Gtime import GetTime
+from .FileManage import bot,VipShopBgDict,config
+from .ShopImg import img_requestor
#下图用于替换违规的vip图片
diff --git a/code/utils/FileManage.py b/code/utils/FileManage.py
index 1e9aee2..ff4b149 100644
--- a/code/utils/FileManage.py
+++ b/code/utils/FileManage.py
@@ -3,8 +3,7 @@
import traceback
from utils.Gtime import GetTime
-FileList = []
-
+FileList = [] # 用于保存需要写入到磁盘的文件
def open_file(path):
with open(path, 'r', encoding='utf-8') as f:
@@ -141,8 +140,10 @@ async def save_aio(self):
SkinNotifyDict = FileManage("./log/UserSkinNotify.json") # 皮肤提醒 用户记录
GameIdDict = FileManage("./log/game_idsave.json") # 玩家游戏id保存
UserAuthID = FileManage("./log/UserAuthID.json") # 用户游戏id/uuid,账户密码重登记录
-UserTokenDict = UserAuthID['data'] # riot用户游戏id和uuid
-UserApLog = UserAuthID['ap_log'] # 账户密码重登记录
+UserRiotName = UserAuthID['data'] # riot用户游戏id和uuid
+UserPwdReauth = UserAuthID['ap_log'] # 账户密码重登记录
+ApiAuthLog = UserAuthID['api_log'] # api 缓存用户的account记录
+ApiAuthCache = {'data':{}} # api EzAuth对象缓存
VipUuidDict = FileManage("./log/VipUuid.json") # vip uuid文件
VipShopBgDict = FileManage("./log/VipUserShopBg.json") # vip 背景图设置;商店图缓存
@@ -152,4 +153,7 @@ async def save_aio(self):
AfdWebhook = FileManage("./log/AfdWebhook.json") # 爱发电的wh请求
+# 实例化一个khl的bot,方便其他模组调用
+from khl import Bot
+bot = Bot(token=config['token']['bot'])
print(f"[FileManage] load all files") # 走到这里代表所有文件都打开了
\ No newline at end of file
diff --git a/code/utils/GrantRoles.py b/code/utils/GrantRoles.py
index e2ff122..67156e8 100644
--- a/code/utils/GrantRoles.py
+++ b/code/utils/GrantRoles.py
@@ -1,14 +1,12 @@
import json
-import time
import aiohttp
from khl import Bot, Message, PublicMessage, Event
from khl.card import Card, CardMessage, Element, Module, Types
-from utils.Gtime import GetTime
# 预加载文件
-from utils.FileManage import SponsorDict, ColorIdDict, EmojiDict
-from utils.KookApi import kook_headers
-
+from .FileManage import SponsorDict, ColorIdDict, EmojiDict
+from .KookApi import kook_headers
+from .Gtime import GetTime
# 用于记录使用表情回应获取ID颜色的用户
def save_userid_color(userid: str, emoji: str):
diff --git a/code/utils/KookApi.py b/code/utils/KookApi.py
index 5656389..ccb73bd 100644
--- a/code/utils/KookApi.py
+++ b/code/utils/KookApi.py
@@ -4,9 +4,7 @@
from khl import Bot, ChannelPrivacyTypes
from khl.card import Card, CardMessage, Module, Element, Types
-from utils.FileManage import config
-# 下方更新卡片消息需要bot
-bot = Bot(token=config['token']['bot'])
+from .FileManage import config,bot
# kook的base_url和headers
kook_base_url = "https://www.kookapp.cn"
kook_headers = {f'Authorization': f"Bot {config['token']['bot']}"}
diff --git a/code/utils/ShopImg.py b/code/utils/ShopImg.py
index 2f1419c..31c80c2 100644
--- a/code/utils/ShopImg.py
+++ b/code/utils/ShopImg.py
@@ -9,8 +9,8 @@
import requests
import zhconv
from PIL import Image, ImageDraw, ImageFont, UnidentifiedImageError
-from utils.valorant.Val import *
-from utils.Gtime import *
+from .valorant.Val import *
+from .Gtime import *
font_color = '#ffffff' # 文字颜色:白色
#用于临时存放图片的dict
diff --git a/code/utils/ShopRate.py b/code/utils/ShopRate.py
index 18f01a8..0e3d00e 100644
--- a/code/utils/ShopRate.py
+++ b/code/utils/ShopRate.py
@@ -4,11 +4,21 @@
import traceback
from khl.card import Card, CardMessage, Module, Element, Types
-# 皮肤的评价
-from utils.valorant import Val
-from utils.FileManage import config,SkinRateDict
-leancloud.init(config["leancloud"]["appid"], master_key=config["leancloud"]["master_key"])
-PLATFORM = "kook"
+from .valorant import Val
+from .FileManage import config,SkinRateDict,GetTime
+PLATFORM = config['platform'] # 平台
+
+# 初始化leancloud
+leancloud.init(config["leancloud"]["appid"], config["leancloud"]["appkey"])
+leanUser = leancloud.User() # 登录用户
+leanUser.login(config["leancloud"]["user_name"],config["leancloud"]["user_pwd"])
+# 设置一个leancloud的acl
+leanAcl = leancloud.ACL()
+leanAcl.set_public_read_access(True) # 所有用户可读
+# 设置当前登录用户的的可写权限
+leanAcl.set_write_access(leancloud.User.get_current().id, True)
+# 设置管理员角色写权限
+leanAcl.set_role_write_access(leancloud.Role('admin'), True)
# 获取皮肤评价的信息
async def get_shop_rate(list_shop: dict, kook_user_id: str):
@@ -42,15 +52,15 @@ async def get_shop_rate(list_shop: dict, kook_user_id: str):
if rate_count > 0:
rate_avg = rate_total // rate_count
#记录当日冠军和屌丝
- if rate_avg > SkinRateDict["cmp"]["best"]["pit"]:
- SkinRateDict["cmp"]["best"]["pit"] = rate_avg
- SkinRateDict["cmp"]["best"]["skin"] = list_shop
- SkinRateDict["cmp"]["best"]["kook_id"] = kook_user_id
+ if rate_avg > SkinRateDict["cmp"]["best"]["rating"]:
+ SkinRateDict["cmp"]["best"]["rating"] = rate_avg
+ SkinRateDict["cmp"]["best"]["list_shop"] = list_shop
+ SkinRateDict["cmp"]["best"]["user_id"] = kook_user_id
print(f"[shop] update rate-best Au:{kook_user_id} = {rate_avg}")
- elif rate_avg < SkinRateDict["cmp"]["worse"]["pit"]:
- SkinRateDict["cmp"]["worse"]["pit"] = rate_avg
- SkinRateDict["cmp"]["worse"]["skin"] = list_shop
- SkinRateDict["cmp"]["worse"]["kook_id"] = kook_user_id
+ elif rate_avg < SkinRateDict["cmp"]["worse"]["rating"]:
+ SkinRateDict["cmp"]["worse"]["rating"] = rate_avg
+ SkinRateDict["cmp"]["worse"]["list_shop"] = list_shop
+ SkinRateDict["cmp"]["worse"]["user_id"] = kook_user_id
print(f"[shop] update rate-worse Au:{kook_user_id} = {rate_avg}")
if rate_avg >= 0 and rate_avg <= 20:
@@ -107,14 +117,14 @@ async def check_shop_rate(kook_user_id: str, list_shop: list):
if rate_count != 0:
rate_avg = rate_total // rate_count #平均分
#记录冠军和屌丝
- if rate_avg > SkinRateDict["cmp"]["best"]["pit"]:
- SkinRateDict["cmp"]["best"]["pit"] = rate_avg
- SkinRateDict["cmp"]["best"]["skin"] = list_shop
- SkinRateDict["cmp"]["best"]["kook_id"] = kook_user_id
- elif rate_avg < SkinRateDict["cmp"]["worse"]["pit"]:
- SkinRateDict["cmp"]["worse"]["pit"] = rate_avg
- SkinRateDict["cmp"]["worse"]["skin"] = list_shop
- SkinRateDict["cmp"]["worse"]["kook_id"] = kook_user_id
+ if rate_avg > SkinRateDict["cmp"]["best"]["rating"]:
+ SkinRateDict["cmp"]["best"]["rating"] = rate_avg
+ SkinRateDict["cmp"]["best"]["list_shop"] = list_shop
+ SkinRateDict["cmp"]["best"]["user_id"] = kook_user_id
+ elif rate_avg < SkinRateDict["cmp"]["worse"]["rating"]:
+ SkinRateDict["cmp"]["worse"]["rating"] = rate_avg
+ SkinRateDict["cmp"]["worse"]["list_shop"] = list_shop
+ SkinRateDict["cmp"]["worse"]["user_id"] = kook_user_id
return True
else:
return False
@@ -142,42 +152,66 @@ async def get_available_skinlist(name:str):
return retlist
# 每日早八,更新leancloud中的ShopCmp
-async def update_ShopCmp():
+from asyncio import Lock
+Slock = Lock() # 需要加锁
+Slock_no = 0 # 计数器
+async def update_ShopCmp(best:dict,worse:dict,platform:str,resetNo = False):
"""update shop rate in leancloud
+ Args: best/worse should be: {
+ "user_id": "938324311",
+ "rating": 97.0,
+ "list_shop": []
+ }
+
+ Return:
+ - { "status":True,"info":"all good"}
+ - { "status":False,"info":err}
"""
try:
- # 获取对象
- ShopCmp = leancloud.Object.extend('ShopCmp')
- query = ShopCmp.query
- # 获取到两个已有值
- query.exists('rating') # 通过键值是否存在,进行查找
- objlist = query.find()
- if len(objlist) == 0:
- raise Exception("leancloud find today err!")
- # 开始更新,先设置为最差
- rate_avg = SkinRateDict["kkn"]["worse"]["pit"]
- list_shop = SkinRateDict["kkn"]["worse"]["skin"]
- kook_user_id = SkinRateDict["kkn"]["worse"]["kook_id"]
- for i in objlist:
- if(i.get('best')): # 是最佳
- if SkinRateDict["kkn"]["best"]["pit"] <= i.get('rating'):
- continue # 当前用户分数小于数据库中的,不更新
- # 设置值
- rate_avg = SkinRateDict["kkn"]["best"]["pit"]
- list_shop = SkinRateDict["kkn"]["best"]["skin"]
- kook_user_id = SkinRateDict["kkn"]["best"]["kook_id"]
- elif(SkinRateDict["kkn"]["worse"]["pit"] >= i.get('rating')): # 是最差,判断分数
- continue # 如果本地用户好于数据库记录,不更新
-
- # 更新对象并保存
- i.set('userId',kook_user_id)
- i.set('skinList',list_shop)
- i.set('rating',rate_avg)
- i.set('platform',PLATFORM)
- i.save()
- print(f"[update_shop_cmp] saving best:{i.get('best')}")
+ # 同一时间只允许一个执行流过来操作ShopCmp
+ global Slock_no
+ if resetNo: Slock_no = 0 # 重置
+ async with Slock:
+ # 获取对象
+ ShopCmp = leancloud.Object.extend('ShopCmp')
+ query = ShopCmp.query
+ # 获取到两个已有值
+ query.exists('rating') # 通过键值是否存在,进行查找
+ objlist = query.find()
+ if len(objlist) <= 1: # 应该有两个才对
+ raise Exception("leancloud find rating err!")
+ # 开始更新,先设置为最差
+ for i in objlist:
+ cur_info = f"best:{i.get('best')} no:{Slock_no}"
+ if(i.get('best')): # 是最佳
+ # 如果不是第一个更新,那就需要判断分数
+ if best["rating"] < i.get('rating') and Slock_no!=0:
+ print(f"[update_ShopCmp] skipping {cur_info}")
+ continue # 当前用户分数小于数据库中的,不更新
+ # 设置值
+ i.set('userId',best["user_id"])
+ i.set('skinList',best["list_shop"])
+ i.set('rating',best["rating"])
+ i.set('platform',platform)
+ i.save()# ShopCmp 设为所有人可写,不需要更新acl
+ elif(worse["rating"] > i.get('rating')) and Slock_no!=0: # 是最差,判断分数
+ print(f"[update_ShopCmp] skipping {cur_info}")
+ continue # 如果本地用户好于数据库记录,不更新
+ else:
+ # 更新对象并保存(不需要比较,而是强制跟新)
+ i.set('userId',worse["user_id"])
+ i.set('skinList',worse["list_shop"])
+ i.set('rating',worse["rating"])
+ i.set('platform',platform)
+ i.save()# ShopCmp 设为所有人可写,不需要更新acl
+ print(f"[update_ShopCmp] saving {cur_info}")
+ # 处理完,no+1
+ Slock_no+=1
+ return { "status":True,"info":"update all good"}
except:
- print(f"ERR! [update_shop_cmp]\n{traceback.format_exc()}")
+ err = f"ERR! [update_ShopCmp]\n{traceback.format_exc()}"
+ print(err)
+ return { "status":False,"info":err}
# 获取昨日最好/最差用户
async def get_ShopCmp():
@@ -251,6 +285,7 @@ async def update_UserCmt(user_id:str,skin_uuid:str):
obj.set('userId',user_id)
obj.set('skinList',skinList)
+ obj.set_acl(leanAcl)
obj.save() # 保存
@@ -319,7 +354,7 @@ async def update_UserRate(skin_uuid:str,rate_info:dict,user_id:str):
- rate_info:{
"name": skin_name,
"cmt": user comment,
- "pit": user rating,
+ "rating": user rating,
"time": time stamp,
"msg_id: message id
}
@@ -340,9 +375,10 @@ async def update_UserRate(skin_uuid:str,rate_info:dict,user_id:str):
obj.set('userId',user_id)
obj.set('comment',rate_info['cmt'])
- obj.set('rating',rate_info['pit'])
+ obj.set('rating',rate_info['rating'])
obj.set('rateAt',rate_info['time'])
obj.set('msgId',rate_info['msg_id'])
+ obj.set_acl(leanAcl)
obj.save() # 保存
@@ -361,7 +397,8 @@ async def update_SkinRate(skin_uuid:str,skin_name:str,rating:float):
# 更新评分
obj.set('rating',rating)
- obj.save() # 保存
+ # obj.set_acl(leanAcl) # 所有人可写,不需要设置acl
+ obj.save() # 保存
# 删除皮肤评价(违规言论)
@@ -379,4 +416,92 @@ async def remove_UserRate(skin_uuid:str,user_id:str):
objlist[0].destroy()
return True
- return False
\ No newline at end of file
+ return False
+
+#########################################hash skin list###############################################
+
+import hashlib
+
+# 生成字符串的MD5值
+def md5(content:str=None):
+ """generate md5 for string
+ """
+ if content is None:
+ return ''
+ md5gen = hashlib.md5()
+ md5gen.update(content.encode())
+ md5code = md5gen.hexdigest()
+ md5gen = None
+ return md5code
+
+
+# 生成字符串的SHA256值
+def sha256(content:str=None):
+ if content is None:
+ return ''
+ sha256gen = hashlib.sha256()
+ sha256gen.update(content.encode())
+ sha256code = sha256gen.hexdigest()
+ sha256gen = None
+ return sha256code
+
+# 生成skinlist的md5
+def get_skinlist_md5(skinlist:list):
+ """Args: skinlist with 4 skin_uuid\n
+ Return: md5(md5+sha) str
+ """
+ skinlist = sorted(skinlist) # 排序
+ # 将uuid拼接
+ strlist = "=".join(i for i in skinlist)
+ md5Ret = md5(strlist) # 计算md5
+ shaRet = sha256(strlist) # 计算sha256
+ return md5(md5Ret+shaRet) # 两个一起还撞车,买彩票去吧
+
+# 判断皮肤的值是否有缓存
+async def query_ShopCache(skinlist:list):
+ """Args: skinlist with 4 skin_uuid\n
+ Info: this def only used by none vip shop img
+
+ Return:{
+ "status": True/False,
+ "img_url": shop img url (will be empty when status False)
+ }
+ """
+ md5Ret = get_skinlist_md5(skinlist)
+ ret = { "status": False,"img_url":""}
+ query = leancloud.Query('ShopCache')
+ query.equal_to('md5',md5Ret) # 查找md5值相同的元素
+ objlist = query.find()
+ if len(objlist) > 0: #找到了
+ ret['img_url'] = objlist[0].get('imgUrl')
+ ret['status'] = True
+ print(f"[{GetTime()}] ShopCache hit! [{md5Ret}]")
+
+ return ret
+
+# 缓存皮肤(先判断出来没有再操作)
+async def update_ShopCache(skinlist:list,img_url:str):
+ """md5(skinlist), cache imgurl to leancloud
+ """
+ md5Ret = get_skinlist_md5(skinlist)
+ ShopCache = leancloud.Object.extend('ShopCache')
+ query = ShopCache.query
+ query.equal_to('md5',md5Ret) # 查找md5值相同的元素
+ objlist = query.find()
+ obj = ShopCache()
+ retBool = True
+ if len(objlist) > 0: #找到了
+ dbSkinlist = objlist[0].get('skinList')
+ if skinlist == dbSkinlist:
+ return True # 已经有了还缓存什么啊
+ else: # md5撞车
+ obj = objlist[0] # 赋值
+ retBool = False
+ # 没找到或者list不相同(md5撞车了),新建并保存
+ obj.set('md5',md5Ret)
+ obj.set('skinList',skinlist)
+ obj.set('imgUrl',img_url)
+ obj.set_acl(leanAcl)
+ obj.save()
+ print(f"[{GetTime()}] update_ShopCache [{md5Ret}]")
+ return retBool
\ No newline at end of file
diff --git a/code/utils/Translate.py b/code/utils/Translate.py
index 7206ee9..6e29b8a 100644
--- a/code/utils/Translate.py
+++ b/code/utils/Translate.py
@@ -6,7 +6,7 @@
from khl.card import Card, CardMessage, Element, Module, Types
# 读取彩云的key
-from utils.FileManage import config
+from .FileManage import config
# 彩云key
CyKey = config['caiyun']
diff --git a/code/utils/api/ApiHandler.py b/code/utils/api/ApiHandler.py
index bb196c3..d731731 100644
--- a/code/utils/api/ApiHandler.py
+++ b/code/utils/api/ApiHandler.py
@@ -2,26 +2,25 @@
import time
import threading
import traceback
-# import requests
-# import asyncio
-from utils.valorant.EzAuth import EzAuthExp, auth2fa, auth2faWait, Get2faWait_Key, User2faCode
+
+from utils.valorant.EzAuth import EzAuthExp,EzAuth
from utils.api.ApiToken import check_token_rate
from utils.Gtime import GetTime
from utils.KookApi import kook_create_asset
from utils.valorant.Val import fetch_daily_shop, fetch_vp_rp_dict
-from utils.ShopImg import get_shop_img_11, get_shop_img_169
+from utils import ShopRate,ShopImg
# bot的配置文件
-from utils.FileManage import config
+from utils.FileManage import config,ApiAuthCache,ApiAuthLog
# 用来给kook上传文件的bot token
api_bot_token = config['token']['api_bot_token']
-Api2faDict = {'data': {}} # 保存2fa用户登录的过程信息
# 默认的背景图
img_bak_169 = 'https://img.kookapp.cn/assets/2022-10/KcN5YoR5hC0zk0k0.jpg'
img_bak_11 = 'https://img.kookapp.cn/assets/2023-01/lzRKEApuEP0rs0rs.jpg'
-# gLock = asyncio.Lock() # 创建一把锁,用于保存文件
+
# # 上传到lsky (这个上传很麻烦,lsky只认open打开的图片)
+# gLock = asyncio.Lock() # 创建一把锁,用于保存文件
# async def lsky_upload(bg):
# await gLock.acquire()# 上锁
# path = "./log/api_img_temp.png"
@@ -56,28 +55,46 @@ async def base_img_request(params, list_shop, vp1=0, rp1=0):
img_src = img_bak_11 # 默认背景1-1
# 开始画图
+ ret = { "status": False,"value":"no need to img draw"} # 初始化ret为不需要画图
+ cacheRet = {"status":False,"img_url":"err" } # 是否需要上传图片(false代表需要)
start = time.perf_counter()
if 'img_ratio' in params and params['img_ratio'] == '1':
- ret = await get_shop_img_11(list_shop, bg_img_src=img_src)
+ # 是1-1的图片,检测有没有使用自定义背景图
+ if img_src == img_bak_11: # 没有自定义背景图
+ # 检测是否有缓存命中
+ cacheRet = await ShopRate.query_ShopCache(list_shop)
+ # 缓存命中失败(需要画图)
+ if not cacheRet['status']:
+ ret = await ShopImg.get_shop_img_11(list_shop, bg_img_src=img_src)
else: # 只有16-9的图片需获取vp和r点
- ret = await get_shop_img_169(list_shop, vp=vp1, rp=rp1, bg_img_src=img_src)
+ ret = await ShopImg.get_shop_img_169(list_shop, vp=vp1, rp=rp1, bg_img_src=img_src)
# 打印计时
print(f"[{GetTime()}] [Api imgDraw]", format(time.perf_counter() - start, '.2f')) # 结果为浮点数,保留两位小数
- start = time.perf_counter()
+ # 开始上传图片
+ start = time.perf_counter() # 更新start计时器
+ # 判断缓存是否命中
+ if cacheRet['status']: # 命中了
+ dailyshop_img_src = cacheRet['img_url']
+ print(f'[{GetTime()}] [Api imgUrl(cache)] {dailyshop_img_src}')
+ return {'code': 0, 'message': dailyshop_img_src, 'info': '商店图片获取成功,缓存命中'}
+ # 缓存没有命中,但是获取画图结果成功
if ret['status']:
bg = ret['value'] # 这个值是pil的结果
img_src_ret = await kook_create_asset(api_bot_token, bg) # 上传图片到kook
# img_src_ret = await lsky_upload(bg) # 上传图片到lsky
- if img_src_ret['code'] == 0:
+ if img_src_ret['code'] == 0: # 上传图片成功
print(f"[{GetTime()}] [Api] kook_create_asset success {format(time.perf_counter() - start, '.2f')}")
dailyshop_img_src = img_src_ret['data']['url']
+ # 初始值是err,调用了query_ShopCache失败,返回值更新为空
+ if cacheRet['img_url'] != 'err':
+ await ShopRate.update_ShopCache(skinlist=list_shop,img_url=dailyshop_img_src)
print(f'[{GetTime()}] [Api imgUrl] {dailyshop_img_src}')
return {'code': 0, 'message': dailyshop_img_src, 'info': '商店图片获取成功'}
- else:
+ else: # 上传图片失败
print(f'[{GetTime()}] [Api] kook_create_asset failed')
return {'code': 200, 'message': 'img upload err', 'info': '图片上传错误'}
- else: #出现图片违规或者url无法获取
+ else: # 出现图片违规或者背景图url无法获取
err_str = ret['value']
print(f'[{GetTime()}] [ERR]', err_str)
return {'code': 200, 'message': 'img src err', 'info': '自定义图片获取失败'}
@@ -105,7 +122,7 @@ async def img_draw_request(request):
return {'code':200,'message':'list_shop len err! should be 4','info':'list_shop长度错误,皮肤数量不为4'}
token = params['token']
- print(list_shop)
+ print(f"[{GetTime()}] [list_shop] {list_shop}")
ck_ret = await check_token_rate(token)
if not ck_ret['status']:
return {'code': 200, 'message': ck_ret['message'], 'info': ck_ret['info']}
@@ -115,9 +132,39 @@ async def img_draw_request(request):
else:
return await base_img_request(params, list_shop, int(params['vp']), int(params['rp']))
+# 获取商店的请求
+async def shop_get_request(params,account:str):
+ # 1.参数检测
+ isRaw = ('raw' in params and str(params['raw']) != '0') # 用户需要原始uuid
+ isimgRatio = ( 'img_ratio' not in params or str(params['img_ratio']) != '1') # 判断是否有指定图片比例
+ # 2.获取缓存中的auth对象
+ if account not in ApiAuthCache['data']:
+ return { "code":200,"message":"account不在ApiAuthCache缓存中,请先调用/login接口",
+ "info":"account not in ApiAuthCache['data']" }
+ # 2.1 判断通过,获取auth
+ auth = ApiAuthCache['data'][account]['auth']
+ assert isinstance(auth,EzAuth)
+ # 2.2 重新登录
+ ret = await auth.reauthorize()
+ if not ret:
+ return { "code":200,"message":"缓存信息失效,需要重新登录",
+ "info":"cache reauthorize failed,please /login" }
+ # 3 获取每日商店
+ riotUser = auth.get_riotuser_token()
+ resp = await fetch_daily_shop(riotUser)
+ print(f'[{GetTime()}] [Api] fetch_daily_shop success')
+ list_shop = resp["SkinsPanelLayout"]["SingleItemOffers"] # 商店刷出来的4把枪
+ res_vprp = {'vp': 0, 'rp': 0} # 先初始化为0
+ if isimgRatio or isRaw:
+ res_vprp = await fetch_vp_rp_dict(riotUser) # 只有16-9的图片需获取vp和r点
+ # 如果用户需要raw,则返回皮肤uuid和vp rp的dict
+ if isRaw:
+ return { "code":0,"message":"获取原始接口返回值成功","info":"get raw response success","storefront":resp,"wallet":res_vprp}
+ else:
+ return await base_img_request(params, list_shop, res_vprp['vp'], res_vprp['rp'])
# 登录+画图
-async def login_img_request(request,method = "GET"):
+async def login_request(request,method = "GET"):
params = request.rel_url.query
if method=="POST":
body = await request.content.read()
@@ -135,22 +182,20 @@ async def login_img_request(request,method = "GET"):
account = params['account']
passwd = params['passwd']
token = params['token']
- isRaw = ('raw' in params and str(params['raw']) != '0') # 用户需要原始uuid
- isimgRatio = ( 'img_ratio' not in params or str(params['img_ratio']) != '1') # 判断是否有指定图片比例
# 检测token速率,避免撞墙
ck_ret = await check_token_rate(token)
if not ck_ret['status']:
return {'code': 200, 'message': ck_ret['message'], 'info': ck_ret['info']}
try:
- key = await Get2faWait_Key()
- Api2faDict['data'][account] = key
- # 因为如果使用异步,该执行流会被阻塞住等待,应该使用线程来操作
- th = threading.Thread(target=auth2fa, args=(account, passwd, key))
- th.start()
- resw = await auth2faWait(key=key) # 随后主执行流来这里等待
- res_auth = resw['auth']
- del Api2faDict['data'][account] # 登录成功,删除账户键值
+ # 登录,获取用户的token
+ auth = EzAuth()
+ resw = await auth.authorize(account,passwd)
+ ApiAuthCache['data'][account] = {"auth": auth, "2fa": auth.is2fa } # 将对象插入
+ # 没有成功,是2fa用户,需要执行/tfa
+ if not resw['status']:
+ return {'code': 0, 'message': "need provide email verify code", 'info': '2fa用户,请使用/tfa接口提供邮箱验证码'}
+
except EzAuthExp.RatelimitError as result:
print(f"ERR! [{GetTime()}] login - EzAuthExp.RatelimitError")
return {'code': 200, 'message': "EzAuthExp.RiotRatelimitError", 'info': 'riot登录api超速,请稍后重试'}
@@ -158,23 +203,16 @@ async def login_img_request(request,method = "GET"):
print(f"ERR! [{GetTime()}] login\n{traceback.format_exc()}")
return {'code': 200, 'message': f"{result}", 'info': 'riot登录错误,详见message'}
- print(f'[{GetTime()}] [Api] k:{key} - user auth success')
- userdict = {
- 'auth_user_id': res_auth.user_id,
- 'access_token': res_auth.access_token,
- 'entitlements_token': res_auth.entitlements_token
- }
- resp = await fetch_daily_shop(userdict) #获取每日商店
- print(f'[{GetTime()}] [Api] fetch_daily_shop success')
- list_shop = resp["SkinsPanelLayout"]["SingleItemOffers"] # 商店刷出来的4把枪
- res_vprp = {'vp': 0, 'rp': 0} # 先初始化为0
- if isimgRatio or isRaw:
- res_vprp = await fetch_vp_rp_dict(userdict) # 只有16-9的图片需获取vp和r点
- # 如果用户需要raw,则返回皮肤uuid和vp rp的dict
- if isRaw:
- return { "code":0,"message":"获取原始接口返回值成功","info":"get raw response success","storefront":resp,"wallet":res_vprp}
- else:
- return await base_img_request(params, list_shop, res_vprp['vp'], res_vprp['rp'])
+ # 走到这里,代表不是2fa用户,且登陆成功
+ print(f'[{GetTime()}] [Api] user auth success')
+ # 如果是GET方法,直接调用获取商店的操作
+ if method == "GET": # /shop-img 接口是get的
+ return await shop_get_request(params,account)
+ # 保存cookie到本地
+ if account not in ApiAuthLog:
+ ApiAuthLog.append(account) # 记录已缓存的用户账户(方便开机加载)
+ auth.save_cookies(f"./log/cookie/api/{account}.cke")
+ return {'code': 0, 'message': "auth success", 'info': '登录成功!'}
# 邮箱验证的post
@@ -194,23 +232,55 @@ async def tfa_code_requeset(request):
vcode = params['vcode']
token = params['token']
- global Api2faDict
- if account not in Api2faDict['data']:
+ global ApiAuthCache
+ if account not in ApiAuthCache['data']:
+ return { 'code': 200,'message': 'Riot account not in ApiAuthCache',
+ 'info': '拳头账户不在dict中,请先请求/shop-img或/login接口' }
+ try:
+ auth = ApiAuthCache['data'][account]['auth']
+ assert isinstance(auth,EzAuth)
+ res = await auth.email_verfiy(vcode)
+ except EzAuthExp.MultifactorError as result:
+ if "multifactor_attempt_failed" in str(result):
+ return { 'code': 200,'message': 'multifactor_attempt_failed',
+ 'info': '两步验证码错误,请在10min内重新调用此接口重传','vcode': vcode }
+ # 其他情况
+ return {'code': 200,'message': '2fa auth_failure','info': '两步验证登陆错误,请重新操作','vcode': vcode}
+ # 走到这里,代表不是2fa用户,且登陆成功
+ print(f'[{GetTime()}] [Api] 2fa user auth success')
+ # 保存cookie到本地
+ if account not in ApiAuthLog:
+ ApiAuthLog.append(account) # 记录已缓存的用户账户(方便开机加载)
+ auth.save_cookies(f"./log/cookie/api/{account}.cke")
+ return {'code': 0, 'message': "2fa auth success", 'info': '2fa用户登录成功!'}
+
+
+# 更新leancloud
+from utils.ShopRate import update_ShopCmp
+async def shop_cmp_request(request):
+ body = await request.content.read()
+ params = json.loads(body.decode('UTF8'))
+ if 'best' not in params or 'worse' not in params or 'token' not in params or 'platform' not in params:
+ print(f"ERR! [{GetTime()}] params needed: token/best/worse/platform")
return {
- 'code': 200,
- 'message': 'Riot account not in Api2faDict',
- 'info': '拳头账户不在dict中,请先请求/shop-img或/shop-url接口'
+ 'code': 400,
+ 'message': 'params needed: token/best/worse/platform',
+ 'info': '缺少参数!请参考api文档,正确设置您的参数',
+ 'docs': 'https://github.com/Aewait/Kook-Valorant-Bot/blob/main/docs/valorant-shop-img-api.md'
}
+
+ best = params['best']
+ worse = params['worse']
+ platform = params['platform']
+ # 调用已有函数更新,保证线程安全
+ upd_ret = await update_ShopCmp(best=best,worse=worse,platform=platform)
+ ret = {'code':0,'message':upd_ret['status'],'info':'ShopCmp更新成功'}
+ # 如果正常,那就是0,否则是200
+ if not upd_ret['status']:
+ ret['code'] = 200
+ ret['info'] = 'ShopCmp更新错误'
- key = Api2faDict['data'][account]
- User2faCode[key]['vcode'] = vcode
- User2faCode[key]['2fa_status'] = True
- return {
- 'code': 0,
- 'message': 'email verify code post success,wait for shop img return',
- 'info': '两步验证码获取成功,请等待主接口返回',
- 'vcode': vcode
- }
+ return ret
from utils.FileManage import AfdWebhook
diff --git a/code/utils/api/ApiToken.py b/code/utils/api/ApiToken.py
index 8e07758..82566c6 100644
--- a/code/utils/api/ApiToken.py
+++ b/code/utils/api/ApiToken.py
@@ -80,6 +80,7 @@ async def token_ck(token: str):
if ApiTokenDict['data'][token]['od_time'] == 0:
od_time = time.time() + ApiTokenDict['data'][token]['days'] * 86400
ApiTokenDict['data'][token]['od_time'] = od_time
+ save_token_files("token init use")
# 用户的token是否过期?
if time.time() > ApiTokenDict['data'][token]['od_time']:
# 过期了,删除该token
@@ -110,7 +111,7 @@ async def check_token_rate(token: str):
if ApiTokenDict['data'][token]['rate_nums'] == 0:
ApiTokenDict['data'][token]['rate_time'] = cur_time
ApiTokenDict['data'][token]['rate_nums'] = 1
- save_token_files("token init use")
+ # save_token_files("token init use")
return {'status': True, 'message': 'first use', 'info': '一切正常'}
# rate_nums不为0,代表检测周期内有调用
elif time_diff <= TOKEN_RATE_TIME: # 和上次调用的时间差在60s以内
@@ -121,7 +122,7 @@ async def check_token_rate(token: str):
ApiTokenDict['data'][token]['rate_nums'] += 1
return {'status': True, 'message': 'time_diff <= 60, in rate', 'info': '一切正常'}
else: # 时间超过60s
- save_token_files("rate check")
+ # save_token_files("rate check")
# 重置rate_time为当前时间,重置计数器(开始新一轮速率检测)
ApiTokenDict['data'][token]['rate_time'] = cur_time
ApiTokenDict['data'][token]['rate_nums'] = 0
diff --git a/code/utils/valorant/EzAuth.py b/code/utils/valorant/EzAuth.py
index 081e52c..7329a3d 100644
--- a/code/utils/valorant/EzAuth.py
+++ b/code/utils/valorant/EzAuth.py
@@ -1,22 +1,18 @@
-# code from https://github.com/Prodzify/Riot-auth/blob/main/main.py
+# repo: https://github.com/musnows/Riot-auth
import ssl
+import json
import time
-import asyncio
-import copy
-import random
import pandas
import requests
from requests.adapters import HTTPAdapter
-from http.cookies import SimpleCookie
from typing import Any
from collections import OrderedDict
from re import compile
-from riot_auth import RiotAuth
-from utils.valorant import EzAuthExp
-
-RiotClient = "RiotClient/62.0.1.4852117.4789131"
-User2faCode = {}
+from . import EzAuthExp
+# get latest version: https://valorant-api.com/v1/version
+X_RIOT_CLIENTVERSION = "RiotClient/63.0.9.4909983.4789131"
+X_RIOT_CLIENTVPLATFROM = "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9"
TFA_TIME_LIMIT = 600 # 600s时间限制
CIPHERS = [
@@ -34,6 +30,7 @@ class URLS:
class SSLAdapter(HTTPAdapter):
+
def init_poolmanager(self, *a: Any, **k: Any) -> None:
c = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
c.set_ciphers(':'.join(CIPHERS))
@@ -41,22 +38,85 @@ def init_poolmanager(self, *a: Any, **k: Any) -> None:
return super(SSLAdapter, self).init_poolmanager(*a, **k)
+# 用于valorant api调用的UserDict
+class RiotUserToken:
+
+ def __init__(self, user_id: str, access_token: str, entitlements: str, region: str) -> None:
+ self.user_id = user_id
+ self.access_token = access_token
+ self.entitlements_token = entitlements
+ self.region = region
+
+
class EzAuth:
- def __init__(self):
+ def __init__(self) -> None:
self.session = requests.Session()
self.session.headers = OrderedDict({
- "User-Agent": f"{RiotClient} %s (Windows;10;;Professional, x64)",
+ "User-Agent": f"{X_RIOT_CLIENTVERSION} %s (Windows;10;;Professional, x64)",
"Accept-Language": "en-US,en;q=0.9",
"Accept": "application/json, text/plain, */*"
})
self.session.mount('https://', SSLAdapter())
- self.is2fa = False # 默认不是2fa用户
+ self.is2fa = False # 2fa set to false
+ self.__mfa_start__ = 0 # 2fa start time
- def authorize(self, username, password, key):
- global User2faCode
+ def __set_userinfo(self) -> None:
+ """set_user_info to value"""
+ userinfo = self.get_userinfo()
+ self.user_id = userinfo['sub']
+ self.Name = userinfo['name']
+ self.Tag = userinfo['tag']
+ self.creationdata = userinfo['create_data']
+ self.typeban = userinfo['typeban']
- data = {
+ def __set_region(self) -> None:
+ self.Region_headers = {
+ 'Content-Type': 'application/json',
+ 'Authorization': f'{self.token_type} {self.access_token}'
+ }
+ self.Region = self.get_region(self.Region_headers)
+
+ def __set_access_token(self, data: dict) -> dict[str, Any]:
+ """get access_token from response"""
+ pattern = compile(
+ 'access_token=((?:[a-zA-Z]|\d|\.|-|_)*).*id_token=((?:[a-zA-Z]|\d|\.|-|_)*).*token_type=((?:[a-zA-Z]|\d|)*).*expires_in=(\d*)'
+ )
+ p_data = pattern.findall(data['response']['parameters']['uri'])[0]
+ tokens = {"access_token": p_data[0], "id_token": p_data[1], "token_type": p_data[2], "expires_in": p_data[3]}
+ return tokens
+
+ def __set_info(self, tokens: dict) -> None:
+ """auth/reauth success, set entitlements_token, userinfo & region\n
+ Args: return value of __set_access_token()
+ """
+ self.access_token = tokens['access_token']
+ self.id_token = tokens['id_token']
+ self.token_type = tokens['token_type']
+
+ self.base_headers = {
+ "User-Agent": f"{X_RIOT_CLIENTVERSION} %s (Windows;10;;Professional, x64)",
+ "Authorization": f"{self.token_type} {self.access_token}",
+ }
+ self.session.headers.update(self.base_headers)
+
+ self.entitlements_token = self.get_entitlement_token()
+ self.__set_userinfo()
+ self.__set_region()
+
+ async def authorize(self, username, password) -> dict:
+ """Authenticate using username and password.\n
+ if username & password empty, using cookie reauth\n
+ Return:
+ - {"status":True,"auth":self,"2fa":self.is2fa}
+ - {"status":False,"auth":self,"2fa_status":self.is2fa}
+ if False, using email_verify() to send verify code
+ """
+ if username and password:
+ self.session.cookies.clear() # not reauth, clear cookie
+
+ token = {"access_token": "", "id_token": "", "token_type": "Bearer", "expires_in": '0'}
+ body = {
"acr_values": "urn:riot:bronze",
"claims": "",
"client_id": "riot-client",
@@ -65,106 +125,90 @@ def authorize(self, username, password, key):
"response_type": "token id_token",
"scope": "openid link ban lol_region",
}
- data2 = {"language": "en_US", "password": password, "remember": "true", "type": "auth", "username": username}
- r = self.session.post(url=URLS.AUTH_URL, json=data)
- r = self.session.put(url=URLS.AUTH_URL, json=data2)
+ r = self.session.post(url=URLS.AUTH_URL, json=body)
data = r.json()
- tokens = ["", ""] # 提前定义,避免下方出错(理论上来说应该走不到下面)
+ resp_type = data["type"]
+
+ if resp_type != "response": # not reauth
+ body = {"language": "en_US", "password": password, "remember": "true", "type": "auth", "username": username}
+ r = self.session.put(url=URLS.AUTH_URL, json=body)
+ data = r.json()
+
+ if data["type"] == "response":
+ pass
+
+ elif "auth_failure" in r.text:
+ raise EzAuthExp.AuthenticationError("auth_failure, user not exist")
+
+ elif 'rate_limited' in r.text:
+ raise EzAuthExp.RatelimitError("auth_failure, rate_limited")
+ # 2fa auth
+ elif 'multifactor' in r.text:
+ print(f"[EzAuth] 2fa user")
+ self.is2fa = True # is 2fa user
+ self.__mfa_start__ = time.time()
+ return {"status": False, "auth": self, "2fa_status": self.is2fa}
+ else:
+ raise EzAuthExp.UnkownError(r.text)
+
+ # get access_token from response
if "access_token" in r.text:
- pattern = compile(
- 'access_token=((?:[a-zA-Z]|\d|\.|-|_)*).*id_token=((?:[a-zA-Z]|\d|\.|-|_)*).*expires_in=(\d*)')
- data = pattern.findall(data['response']['parameters']['uri'])[0]
- token = data[0]
- token_id = data[1]
- tokens = [token, token_id]
-
- elif "auth_failure" in r.text:
- User2faCode[key] = {'status': False, 'err': f"[{key}] auth_failure, USER NOT EXIST",
- 'start_time': time.time(),'2fa_status':True}
- raise EzAuthExp.AuthenticationError(User2faCode[key]['err'])
-
- elif 'rate_limited' in r.text:
- User2faCode[key] = {'status': False, 'err': f"[{key}] auth rate_limited", 'start_time': time.time(),'2fa_status':True}
- raise EzAuthExp.RatelimitError(User2faCode[key]['err'])
-
- else: # 到此处是需要邮箱验证的用户
- print(f"[EzAuth] k:{key} 2fa user")
- self.is2fa = True # 是2fa用户
- User2faCode[key] = {
- 'vcode': '',
- 'status': False,
- 'start_time': time.time(),
- '2fa_status': False,
- 'err': None
- }
- # 开始等待用户提供邮箱验证码
- while (not User2faCode[key]['2fa_status']):
- if (time.time() - User2faCode[key]['start_time']) > TFA_TIME_LIMIT:
- break # 超过10分钟,以无效处理
- time.sleep(0.2) # 因为是线程执行操作,不能线程+异步
-
- # 再次判断,避免是超时break的
- if User2faCode[key]['2fa_status']:
- #需要用户通过命令键入邮箱验证码
- authdata = {
- 'type': 'multifactor',
- 'code': User2faCode[key]['vcode'],
- }
- r = self.session.put(url=URLS.AUTH_URL, json=authdata)
- data = r.json()
- if "access_token" in r.text:
- pattern = compile(
- 'access_token=((?:[a-zA-Z]|\d|\.|-|_)*).*id_token=((?:[a-zA-Z]|\d|\.|-|_)*).*expires_in=(\d*)')
- data = pattern.findall(data['response']['parameters']['uri'])[0]
- token = data[0]
- token_id = data[1]
- tokens = [token, token_id]
-
- elif "auth_failure" in r.text:
- User2faCode[key]['err'] = f"[{key}] 2fa auth_failue"
- raise EzAuthExp.MultifactorError(User2faCode[key]['err'])
- elif "multifactor_attempt_failed" in r.text: # 大概率是验证码错了
- User2faCode[key]['err'] = f"[{key}] 2fa auth_failue, multifactor_attempt_failed"
- raise EzAuthExp.MultifactorError(User2faCode[key]['err'])
- else:
- User2faCode[key]['err'] = f"[{key}] 2fa auth_failue, unkown err"
- raise EzAuthExp.MultifactorError(User2faCode[key]['err'])
- else: # 2fa等待超出600s
- User2faCode[key]['err']=f"[{key}] 2fa wait overtime, wait failed"
- raise EzAuthExp.WaitOvertimeError(User2faCode[key]['err'])
-
- # auth success
- self.access_token = tokens[0]
- self.id_token = tokens[1]
+ token = self.__set_access_token(data)
+ # auth/reauth success
+ self.__set_info(tokens=token)
+ else:
+ raise EzAuthExp.UnkownError(r.text)
- self.base_headers = {
- 'User-Agent': f"{RiotClient} %s (Windows;10;;Professional, x64)",
- 'Authorization': f'Bearer {self.access_token}',
- }
- self.session.headers.update(self.base_headers)
- self.cookie = self.session.cookies
+ return {"status": True, "auth": self, "2fa_status": self.is2fa}
- self.entitlements_token = self.get_entitlement_token()
- self.emailverifed = self.get_emailverifed()
+ async def email_verfiy(self, vcode: str) -> dict:
+ """email_verfiy after trying authorize
+ Return {"status":True,"auth":self,"2fa":self.is2fa}
+ """
+ # no need to 2fa
+ if self.__mfa_start__ == 0:
+ return {"status": True, "auth": self, "2fa": self.is2fa}
+ # check time
+ if (time.time() - self.__mfa_start__) <= TFA_TIME_LIMIT:
+ authdata = {
+ 'type': 'multifactor',
+ 'code': vcode,
+ }
+ r = self.session.put(url=URLS.AUTH_URL, json=authdata)
+ data = r.json()
+
+ if data["type"] == "response":
+ pass
+ elif "auth_failure" in r.text:
+ raise EzAuthExp.MultifactorError("2fa auth_failue")
+ elif "multifactor_attempt_failed" in r.text: # verify code err
+ raise EzAuthExp.MultifactorError("2fa auth_failue, multifactor_attempt_failed")
+ else:
+ raise EzAuthExp.MultifactorError("2fa auth_failue, unkown err")
+ else: # 2fa wait overtime
+ raise EzAuthExp.WaitOvertimeError("2fa wait overtime, wait failed")
+
+ # get access_token from response
+ if "access_token" in r.text:
+ token = self.__set_access_token(data)
+ # auth/reauth success
+ self.__set_info(tokens=token)
+ else:
+ raise EzAuthExp.UnkownError(r.text)
- userinfo = self.get_userinfo()
- self.user_id = userinfo['sub']
- self.Name = userinfo['name']
- self.Tag = userinfo['tag']
- self.creationdata = userinfo['create_data']
- self.typeban = userinfo['typeban']
- self.Region_headers = {'Content-Type': 'application/json', 'Authorization': f'Bearer {self.access_token}'}
- self.session.headers.update(self.Region_headers)
- self.Region = self.get_Region()
- # return self
- User2faCode[key] = {
- 'status': True,
- 'auth': self,
- 'err': None,
- '2fa_status':True
- }
- print(f"[EzAuth] k:{key} auth success")
+ self.__mfa_start__ = 0
+ return {"status": True, "auth": self, "2fa": self.is2fa}
+
+ async def reauthorize(self) -> bool:
+ """reauthorize using cookie
+ """
+ try:
+ await self.authorize("", "")
+ return True
+ except Exception as result:
+ print(f"[EzAuth] reauthoreize err!\n{result}")
+ return False
def get_entitlement_token(self):
r = self.session.post(URLS.ENTITLEMENT_URL, json={})
@@ -208,17 +252,20 @@ def get_userinfo(self):
typeban = "PERMANENT_BAN"
if data3 == [] or "PBE_LOGIN_TIME_BAN" in data3 or "LEGACY_BAN" in data3:
typeban = "None"
- return {'sub':Sub, 'name':Name, 'tag':Tag, 'create_data':Createdat, 'typeban':typeban}
+ return {'sub': Sub, 'name': Name, 'tag': Tag, 'create_data': Createdat, 'typeban': typeban}
- def get_Region(self):
+ def get_region(self, headers) -> str:
+ """headers {'Content-Type': 'application/json', 'Authorization': f'{self.token_type} {self.access_token}'}
+ """
json = {"id_token": self.id_token}
+ r = self.session.headers.update(headers)
r = self.session.put('https://riot-geo.pas.si.riotgames.com/pas/v1/product/valorant', json=json)
data = r.json()
Region = data['affinities']['live']
return Region
- def print(self):
- print()
+ def print(self) -> None:
+ print("=" * 50)
print(f"Accestoken: {self.access_token}")
print("-" * 50)
print(f"Entitlements: {self.entitlements_token}")
@@ -232,98 +279,31 @@ def print(self):
print(f"Createdat: {self.creationdata}")
print("-" * 50)
print(f"Bantype: {self.typeban}")
+ print("=" * 50)
- def get_Token(self):
- userdict = {
- 'auth_user_id': self.user_id,
- 'access_token': self.access_token,
- 'entitlements_token': self.entitlements_token
- }
- return userdict
-
- def get_CookieDict(self):
- # cookie转换成dict
- ck_dict = requests.utils.dict_from_cookiejar(self.cookie)
- return ck_dict
-
- async def get_RiotAuth(self):
- # cookie dict导入到SimpleCookie
- Scookie = SimpleCookie(self.get_CookieDict())
- rauth = RiotAuth()
- # 更新cookie
- rauth._cookie_jar.update_cookies(Scookie)
- ret = await rauth.reauthorize() # 测试登录
- if ret:
- return rauth
- else: #失败返回None
- raise Exception('EzAuth change to RiotAuth failed')
-
-
-###################################### Riot Auth ######################################################
-
-
-# 获取拳头的token
-# 此部分代码来自 https://github.com/floxay/python-riot-auth
-async def authflow(user: str, passwd: str):
- CREDS = user, passwd
- auth = RiotAuth()
- await auth.authorize(*CREDS)
- # await auth.reauthorize()
- # print(f"Access Token Type: {auth.token_type}\n",f"Access Token: {auth.access_token}\n")
- # print(f"Entitlements Token: {auth.entitlements_token}\n",f"User ID: {auth.user_id}")
- return auth
-
-
-# 两步验证的用户
-def auth2fa(user: str, passwd: str, key: str):
- auth = EzAuth()
- auth.authorize(user, passwd, key=key)
-
-
-# 轮询检测的等待
-async def auth2faWait(key, msg=None):
- while True:
- if key in User2faCode:
- # 如果2fa_status为假,代表是2fa且账户密码没有问题,需要用户提供vcode
- if not User2faCode[key]['2fa_status']:
- print(f"[auth2faWait] k:{key} 2fa Wait")
- if msg != None:
- await msg.reply(f"您开启了邮箱双重验证,请使用「/tfa {key} 邮箱码」的方式验证\n栗子:若邮箱验证码为114514,那么您应该键入 `/tfa {key} 114514`"
- )
-
- # 开始循环检测status状态
- while (not User2faCode[key]['status']):
- # 不为none,出现错误
- if User2faCode[key]['err'] != None:
- if 'rate_limited' in User2faCode[key]['err']:
- raise EzAuthExp.RatelimitError(User2faCode[key]['err'])
- elif 'auth_failure' in User2faCode[key]['err']:
- raise EzAuthExp.AuthenticationError(User2faCode[key]['err'])
- elif 'overtime' in User2faCode[key]['err']:
- del User2faCode[key]
- raise EzAuthExp.WaitOvertimeError(User2faCode[key]['err'])
- else:
- raise EzAuthExp.UnkownError(User2faCode[key]['err'])
-
- # 睡一会再检测
- await asyncio.sleep(0.3)
-
- # 如果退出且为真,代表登录成功了
- if User2faCode[key]['status']:
- ret = copy.deepcopy(User2faCode[key])
- del User2faCode[key]
- print(f"[auth2faWait] k:{key} Wait success,del key")
- return ret
- else: # 走到这里没有被raise,出现了未知错误
- print(f"[auth2faWait] k:{key} Wait failed, unkown err")
- raise EzAuthExp.UnkownError("auth2faWait Failed")
- # key值不在,睡一会后再看看
- await asyncio.sleep(0.2)
-
-
-async def Get2faWait_Key():
- ran = random.randint(1, 9999)
- while (ran in User2faCode):
- ran = random.randint(1, 9999) # 创建一个1-9999的随机值
- # 直到创建出了一个不在其中的键值
- return ran
\ No newline at end of file
+ def get_riotuser_token(self) -> RiotUserToken:
+ """RiotUserToken(user_id=self.user_id,
+ access_token=self.access_token,
+ entitlements=self.entitlements_token,
+ region=self.Region)
+ """
+ ret = RiotUserToken(user_id=self.user_id,
+ access_token=self.access_token,
+ entitlements=self.entitlements_token,
+ region=self.Region)
+ return ret
+
+ def save_cookies(self, path: str) -> None:
+ """dump cookies_dict to path (w+)
+ """
+ cookies = requests.utils.dict_from_cookiejar(self.session.cookies) # type: ignore
+ with open(path, "w+") as f:
+ f.write(json.dumps(cookies))
+
+ def load_cookies(self, path: str) -> None:
+ """load cookies_dic from path (rb)
+ """
+ with open(path, "r") as f:
+ load_cookies = json.loads(f.read())
+
+ self.session.cookies = requests.utils.cookiejar_from_dict(load_cookies) # type: ignore
\ No newline at end of file
diff --git a/code/utils/valorant/Val.py b/code/utils/valorant/Val.py
index da99a19..9056047 100644
--- a/code/utils/valorant/Val.py
+++ b/code/utils/valorant/Val.py
@@ -1,18 +1,18 @@
# encoding: utf-8:
import json
import aiohttp
-from khl import Bot, Message
-from khl.card import Card, CardMessage, Element, Module, Types
+from khl import Message
+from khl.card import Card, Element, Module, Types
# 预加载文件
-from utils.FileManage import GameIdDict, ValErrDict, ValBundleList, ValItersList, ValPriceList, ValSkinList
+from .EzAuth import X_RIOT_CLIENTVERSION,X_RIOT_CLIENTVPLATFROM,RiotUserToken
+from ..FileManage import GameIdDict, ValErrDict, ValItersList, ValPriceList, ValSkinList
SKIN_ICON_ERR = "https://img.kookapp.cn/assets/2023-02/ekwdy7PiQC0e803m.png"
-X_RIOT_CLIENTVERSION = "release-06.01-shipping-8-820493"
####################################保存用户的游戏ID操作#######################################
#保存用户id
-async def saveid_main(msg: Message, game_id: str):
+async def saveid_main(msg: Message, game_id: str) -> None:
global GameIdDict
flag = 0
# 如果用户id已有,则进行修改
@@ -28,13 +28,13 @@ async def saveid_main(msg: Message, game_id: str):
# 显示已有id的个数
-async def saveid_count(msg: Message):
+async def saveid_count(msg: Message) -> None:
countD = len(GameIdDict)
await msg.reply(f"目前狸狸已经记下了`{countD}`个小伙伴的id喽~")
# 实现读取用户游戏ID并返回
-async def myid_main(msg: Message):
+async def myid_main(msg: Message) -> None:
if msg.author_id in GameIdDict.keys():
flag = 1 #找到了对应用户的id
await msg.reply(f'游戏id: ' + GameIdDict[msg.author_id])
@@ -47,7 +47,7 @@ async def myid_main(msg: Message):
# 查询游戏错误码
-async def val_errcode(msg: Message, num: str = "-1"):
+async def val_errcode(msg: Message, num: str = "-1") -> None:
if num == "-1":
await msg.reply(
'目前支持查询的错误信息有:\n```\n0-1,4-5,7-21,29,31,33,38,43-46,49-70,81,84,128,152,1067,9001,9002,9003\n```\n注:van和val错误码都可用本命令查询'
@@ -59,7 +59,7 @@ async def val_errcode(msg: Message, num: str = "-1"):
#关于dx报错的解决方法
-async def dx123(msg: Message):
+async def dx123(msg: Message) -> None:
await msg.reply(
'报错弹窗内容为`The following component(s) are required to run this program:DirectX Runtime`\n需要下载微软官方驱动安装,官网搜索[DirectX End-User Runtime Web Installer]\n你还可以下载本狸亲测可用的DX驱动 [链接](https://pan.baidu.com/s/1145Ll8vGtByMW6OKk6Zi2Q),暗号是1067哦!\n狸狸记得之前玩其他游戏的时候,也有遇到过这个问题呢~'
)
@@ -69,14 +69,14 @@ async def dx123(msg: Message):
#从list中获取价格
-def fetch_item_price_bylist(item_id):
+def fetch_item_price_bylist(item_id) -> dict | None:
for item in ValPriceList['Offers']: #遍历查找指定uuid
if item_id == item['OfferID']:
return item
#从list中获取等级(这个需要手动更新)
-def fetch_item_iters_bylist(iter_id):
+def fetch_item_iters_bylist(iter_id) -> dict | None:
for iter in ValItersList['data']: #遍历查找指定uuid
if iter_id == iter['uuid']:
res = {'data': iter} #所以要手动创建一个带data的dict作为返回值
@@ -84,7 +84,7 @@ def fetch_item_iters_bylist(iter_id):
#从list中获取皮肤
-def fetch_skin_bylist(item_id):
+def fetch_skin_bylist(item_id) -> dict | None:
res = {} #下面我们要操作的是获取通行证的皮肤,但是因为遍历的时候已经跳过data了,返回的时候就不好返回
for item in ValSkinList['data']: #遍历查找指定uuid
if item_id == item['levels'][0]['uuid']:
@@ -102,7 +102,7 @@ def fetch_skin_bylist(item_id):
#从list中,通过皮肤名字获取皮肤列表
-def fetch_skin_list_byname(name):
+def fetch_skin_list_byname(name) ->list[dict]:
wplist = list() #包含该名字的皮肤list
for skin in ValSkinList['data']:
if name in skin['displayName']:
@@ -112,7 +112,7 @@ def fetch_skin_list_byname(name):
#从list中通过皮肤lv0uuid获取皮肤等级
-def fetch_skin_iters_bylist(item_id):
+def fetch_skin_iters_bylist(item_id) -> dict | None:
for it in ValSkinList['data']:
if it['levels'][0]['uuid'] == item_id:
res_iters = fetch_item_iters_bylist(it['contentTierUuid'])
@@ -120,7 +120,7 @@ def fetch_skin_iters_bylist(item_id):
# 用名字查询捆绑包包含什么枪
-async def fetch_bundle_weapen_byname(name):
+async def fetch_bundle_weapen_byname(name)->list[dict]:
# 捆绑包的所有皮肤
WeapenList = list()
for skin in ValSkinList['data']:
@@ -138,13 +138,13 @@ async def fetch_bundle_weapen_byname(name):
#获取用户游戏id(从使用对象修改成使用文件中的内容)
-async def fetch_user_gameID(auth):
+async def fetch_user_gameID(ru:RiotUserToken) -> dict:
url = "https://pd.ap.a.pvp.net/name-service/v2/players"
- payload = json.dumps([auth['auth_user_id']])
+ payload = json.dumps([ru.user_id])
headers = {
"Content-Type": "application/json",
- "X-Riot-Entitlements-JWT": auth['entitlements_token'],
- "Authorization": "Bearer " + auth['access_token']
+ "X-Riot-Entitlements-JWT": ru.entitlements_token,
+ "Authorization": "Bearer " + ru.access_token
}
async with aiohttp.ClientSession() as session:
async with session.put(url, headers=headers, data=payload) as response:
@@ -153,12 +153,12 @@ async def fetch_user_gameID(auth):
# 获取每日商店
-async def fetch_daily_shop(u):
- url = "https://pd.ap.a.pvp.net/store/v2/storefront/" + u['auth_user_id']
+async def fetch_daily_shop(ru:RiotUserToken)-> dict:
+ url = "https://pd.ap.a.pvp.net/store/v2/storefront/" + ru.user_id
headers = {
"Content-Type": "application/json",
- "X-Riot-Entitlements-JWT": u['entitlements_token'],
- "Authorization": "Bearer " + u['access_token']
+ "X-Riot-Entitlements-JWT": ru.entitlements_token,
+ "Authorization": "Bearer " + ru.access_token
}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers) as response:
@@ -167,12 +167,12 @@ async def fetch_daily_shop(u):
# Api获取玩家的vp和r点
-async def fetch_valorant_point(u):
- url = "https://pd.ap.a.pvp.net/store/v1/wallet/" + u['auth_user_id']
+async def fetch_valorant_point(ru:RiotUserToken)-> dict:
+ url = "https://pd.ap.a.pvp.net/store/v1/wallet/" + ru.user_id
headers = {
"Content-Type": "application/json",
- "X-Riot-Entitlements-JWT": u['entitlements_token'],
- "Authorization": "Bearer " + u['access_token']
+ "X-Riot-Entitlements-JWT": ru.entitlements_token,
+ "Authorization": "Bearer " + ru.access_token
}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers) as response:
@@ -181,20 +181,20 @@ async def fetch_valorant_point(u):
# 获取vp和r点的dict
-async def fetch_vp_rp_dict(u):
- resp = await fetch_valorant_point(u)
+async def fetch_vp_rp_dict(ru:RiotUserToken)-> dict[str,int]:
+ resp = await fetch_valorant_point(ru)
vp = resp["Balances"]["85ad13f7-3d1b-5128-9eb2-7cd8ee0b5741"] #vp
rp = resp["Balances"]["e59aa87c-4cbf-517a-5983-6e81511be9b7"] #R点
return {'vp': vp, 'rp': rp}
# 获取商品价格(所有)
-async def fetch_item_price_all(u):
+async def fetch_item_price_all(ru:RiotUserToken)-> dict:
url = "https://pd.ap.a.pvp.net/store/v1/offers/"
headers = {
"Content-Type": "application/json",
- "X-Riot-Entitlements-JWT": u['entitlements_token'],
- "Authorization": "Bearer " + u['access_token']
+ "X-Riot-Entitlements-JWT": ru.entitlements_token,
+ "Authorization": "Bearer " + ru.access_token
}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers) as response:
@@ -204,8 +204,8 @@ async def fetch_item_price_all(u):
# 获取商品价格(用uuid获取单个价格)
-async def fetch_item_price_uuid(u, item_id: str):
- res = await fetch_item_price_all(u) #获取所有价格
+async def fetch_item_price_uuid(ru:RiotUserToken, item_id: str)-> str:
+ res = await fetch_item_price_all(ru) #获取所有价格
for item in res['Offers']: #遍历查找指定uuid
if item_id == item['OfferID']:
@@ -215,7 +215,7 @@ async def fetch_item_price_uuid(u, item_id: str):
# 获取皮肤等级(史诗/传说)
-async def fetch_item_iters(iters_id: str):
+async def fetch_item_iters(iters_id: str)-> dict:
url = "https://valorant-api.com/v1/contenttiers/" + iters_id
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -227,7 +227,7 @@ async def fetch_item_iters(iters_id: str):
# 获取所有皮肤
-async def fetch_skins_all():
+async def fetch_skins_all()->dict:
url = "https://valorant-api.com/v1/weapons/skins"
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -239,7 +239,7 @@ async def fetch_skins_all():
# 获取所有皮肤捆绑包
-async def fetch_bundles_all():
+async def fetch_bundles_all()->dict:
url = "https://valorant-api.com/v1/bundles"
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -251,12 +251,12 @@ async def fetch_bundles_all():
# 获取获取玩家当前装备的卡面和称号
-async def fetch_player_loadout(u):
- url = f"https://pd.ap.a.pvp.net/personalization/v2/players/{u['auth_user_id']}/playerloadout"
+async def fetch_player_loadout(ru:RiotUserToken)->dict:
+ url = f"https://pd.ap.a.pvp.net/personalization/v2/players/{ru.user_id}/playerloadout"
headers = {
"Content-Type": "application/json",
- "X-Riot-Entitlements-JWT": u['entitlements_token'],
- "Authorization": "Bearer " + u['access_token'],
+ "X-Riot-Entitlements-JWT": ru.entitlements_token,
+ "Authorization": "Bearer " + ru.access_token,
'Connection': 'close'
}
async with aiohttp.ClientSession() as session:
@@ -267,16 +267,14 @@ async def fetch_player_loadout(u):
# 获取合约(任务)进度
-# client version from https://valorant-api.com/v1/version
-async def fetch_player_contract(u):
+async def fetch_player_contract(ru:RiotUserToken)->dict:
#url="https://pd.ap.a.pvp.net/contract-definitions/v2/definitions/story"
- url = f"https://pd.ap.a.pvp.net/contracts/v1/contracts/" + u['auth_user_id']
+ url = f"https://pd.ap.a.pvp.net/contracts/v1/contracts/" + ru.user_id
headers = {
"Content-Type": "application/json",
- "X-Riot-Entitlements-JWT": u['entitlements_token'],
- "Authorization": "Bearer " + u['access_token'],
- "X-Riot-ClientPlatform":
- "ew0KCSJwbGF0Zm9ybVR5cGUiOiAiUEMiLA0KCSJwbGF0Zm9ybU9TIjogIldpbmRvd3MiLA0KCSJwbGF0Zm9ybU9TVmVyc2lvbiI6ICIxMC4wLjE5MDQyLjEuMjU2LjY0Yml0IiwNCgkicGxhdGZvcm1DaGlwc2V0IjogIlVua25vd24iDQp9",
+ "X-Riot-Entitlements-JWT": ru.entitlements_token,
+ "Authorization": "Bearer " + ru.access_token,
+ "X-Riot-ClientPlatform": X_RIOT_CLIENTVPLATFROM,
"X-Riot-ClientVersion": X_RIOT_CLIENTVERSION
}
async with aiohttp.ClientSession() as session:
@@ -286,12 +284,12 @@ async def fetch_player_contract(u):
return res
# 获取玩家的等级信息
-async def fetch_player_level(u):
- url = "https://pd.ap.a.pvp.net/account-xp/v1/players/"+ u['auth_user_id']
+async def fetch_player_level(ru:RiotUserToken) -> dict:
+ url = "https://pd.ap.a.pvp.net/account-xp/v1/players/"+ ru.user_id
headers = {
"Content-Type": "application/json",
- "X-Riot-Entitlements-JWT": u['entitlements_token'],
- "Authorization": "Bearer " + u['access_token'],
+ "X-Riot-Entitlements-JWT": ru.entitlements_token,
+ "Authorization": "Bearer " + ru.access_token,
}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers) as response:
@@ -300,7 +298,7 @@ async def fetch_player_level(u):
return res
# 获取玩家当前通行证情况,uuid
-async def fetch_contract_uuid(id):
+async def fetch_contract_uuid(id:str) -> dict:
url = "https://valorant-api.com/v1/contracts/" + id
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -312,7 +310,7 @@ async def fetch_contract_uuid(id):
# 获取玩家卡面,uuid
-async def fetch_playercard_uuid(id):
+async def fetch_playercard_uuid(id:str)-> dict:
url = "https://valorant-api.com/v1/playercards/" + id
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -324,7 +322,7 @@ async def fetch_playercard_uuid(id):
# 获取玩家称号,uuid
-async def fetch_title_uuid(id):
+async def fetch_title_uuid(id:str)-> dict:
url = "https://valorant-api.com/v1/playertitles/" + id
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -336,7 +334,7 @@ async def fetch_title_uuid(id):
# 获取喷漆,uuid
-async def fetch_spary_uuid(id):
+async def fetch_spary_uuid(id:str)-> dict:
url = "https://valorant-api.com/v1/sprays/" + id
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -348,7 +346,7 @@ async def fetch_spary_uuid(id):
# 获取吊坠,uuid
-async def fetch_buddies_uuid(id):
+async def fetch_buddies_uuid(id:str)->dict:
url = "https://valorant-api.com/v1/buddies/levels/" + id
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -360,7 +358,7 @@ async def fetch_buddies_uuid(id):
# 获取皮肤,通过lv0的uuid
-async def fetch_skinlevel_uuid(id):
+async def fetch_skinlevel_uuid(id:str)->dict:
url = f"https://valorant-api.com/v1/weapons/skinlevels/" + id
headers = {'Connection': 'close'}
params = {"language": "zh-TW"}
@@ -406,7 +404,7 @@ async def get_reward(reward):
# 创建一个玩家任务和通信证的卡片消息
-async def create_cm_contract(msg: Message):
+async def create_cm_contract(msg: Message) -> Card:
# 预加载用户token(其实已经没用了)
with open("./log/UserAuthID.json", 'r', encoding='utf-8') as frau:
UserTokenDict = json.load(frau)
diff --git a/code/utils/valorant/ValFileUpd.py b/code/utils/valorant/ValFileUpd.py
index c208401..f23523d 100644
--- a/code/utils/valorant/ValFileUpd.py
+++ b/code/utils/valorant/ValFileUpd.py
@@ -1,15 +1,15 @@
import traceback
-import json
import io
from khl import Message, Bot
from PIL import Image
-from utils.Gtime import GetTime
-from utils.ShopImg import img_requestor
-from utils.valorant.Val import fetch_skins_all, fetch_item_price_all, fetch_bundles_all, ValBundleList, ValSkinList, ValPriceList
+from ..Gtime import GetTime
+from ..ShopImg import img_requestor
+from ..FileManage import ValBundleList
+from .Val import fetch_skins_all, fetch_item_price_all, fetch_bundles_all, ValSkinList, ValPriceList
# 更新本地保存的皮肤
-async def update_skins(msg: Message):
+async def update_skins(msg: Message) -> bool:
try:
global ValSkinList
skins = await fetch_skins_all()
@@ -26,14 +26,14 @@ async def update_skins(msg: Message):
# 更新捆绑包
-async def update_bundle_url(msg: Message, bot_upimg: Bot):
+async def update_bundle_url(msg: Message, bot_upimg: Bot) -> bool:
try:
global ValBundleList
resp = await fetch_bundles_all() #从官方获取最新list
if len(resp['data']) == len(ValBundleList): #长度相同代表没有更新
print(f"[{GetTime()}] len is the same, doesn't need update!")
await msg.reply("BundleList_len相同,无需更新")
- return
+ return True
for b in resp['data']:
flag = 0
@@ -64,7 +64,7 @@ async def update_bundle_url(msg: Message, bot_upimg: Bot):
# 因为下方获取物品价格的操作需要authtoken,自动更新容易遇到token失效的情况
-async def update_price(msg: Message, userdict):
+async def update_price(msg: Message, userdict) -> bool:
try:
global ValPriceList
# 调用api获取价格列表
diff --git a/docs/leancloud.md b/docs/leancloud.md
index 7f1c633..f0bc25d 100644
--- a/docs/leancloud.md
+++ b/docs/leancloud.md
@@ -59,7 +59,7 @@
建议在本地维护一个当天(8am之后)的用户最好/最差商店信息,并在次日8am更新到数据库。数据库中维护的是**昨日商店**的最高分/最低分。
-由于leancloud的结构化数据存储并不是[线程安全](https://docs.leancloud.cn/sdk/storage/guide/python/#%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8)的,为了避免多个项目同时在8am访问并更新ShopCmp,请加入开发者频道和我确认,约定一个时间(不同项目错开)来更新数据!
+由于leancloud的结构化数据存储并不是[线程安全](https://docs.leancloud.cn/sdk/storage/guide/python/#%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8)的,为了避免多个项目同时在8am访问并更新ShopCmp,请调用 [api/shop-cmp](valorant-shop-img-api.md) 接口进行更新
## 4.UserCmt
diff --git a/docs/valorant-shop-img-api.md b/docs/valorant-shop-img-api.md
index d33e894..1b73c1e 100644
--- a/docs/valorant-shop-img-api.md
+++ b/docs/valorant-shop-img-api.md
@@ -2,7 +2,7 @@
> Api展示页 https://val.musnow.top/
>
-> Api根连接 https://val.musnow.top/api/
+> Api根连接 https://val.musnow.top/api/v2/
Api是一个网页链接,能够方便的被用户使用或被开发者调用,以实现特定功能。
@@ -29,7 +29,7 @@ Api是一个网页链接,能够方便的被用户使用或被开发者调用
由于该接口会直接跳转到图片,所以不支持开启了邮箱验证的用户,也不建议开发者调用
~~~
-https://val.musnow.top/api/shop-img?token=API的密钥&account=账户&passwd=密码
+https://val.musnow.top/api/v2/shop-img?token=API的密钥&account=账户&passwd=密码
~~~
补充好上面的链接后,直接丢浏览器里面打开就OK。可以浏览器收藏一下,方便后续查看!
@@ -41,18 +41,18 @@ https://val.musnow.top/api/shop-img?token=API的密钥&account=账户&passwd=密
若要添加自定义背景图,则链接应该如下
~~~
-https://val.musnow.top/api/shop-img?token=API的密钥&account=账户&passwd=密码&img_src=背景图片链接
+https://val.musnow.top/api/v2/shop-img?token=API的密钥&account=账户&passwd=密码&img_src=背景图片链接
~~~
如果背景图是正方形(1-1)
~~~
-https://val.musnow.top/api/shop-img?token=API的密钥&account=账户&passwd=密码&img_src=背景图片链接&img_ratio=1
+https://val.musnow.top/api/v2/shop-img?token=API的密钥&account=账户&passwd=密码&img_src=背景图片链接&img_ratio=1
~~~
自定义背景图请求示例(16-9)
~~~
-https://val.musnow.top/api/shop-img?token=API的密钥&account=账户&passwd=密码&img_src=https://img.kookapp.cn/assets/2022-09/KV5krdRx080qo0f0.jpg
+https://val.musnow.top/api/v2/shop-img?token=API的密钥&account=账户&passwd=密码&img_src=https://img.kookapp.cn/assets/2022-09/KV5krdRx080qo0f0.jpg
~~~
结果示例图(16-9)
@@ -82,21 +82,20 @@ https://val.musnow.top/api/shop-img?token=API的密钥&account=账户&passwd=密
### 3.1 shop
-如果你是开发者,请使用`/shop`来获取`json`格式的结果
+如果你是开发者,请使用`/shop`来获取`json`格式的结果;
+
+注意,请求此接口之前,请先请求 `/login` 和 `/tfa`
~~~
-https://val.musnow.top/api/shop
+https://val.musnow.top/api/v2/shop
~~~
请求方法: `POST`
-速率限制:`10r/m`
-
| body参数 | 说明 | 参数类型 |是否必填 |
| ---------- | --------------------- | -------- | -------- |
| token | API token | string|是 |
| account | 拳头账户 | string |是 |
-| passwd | 拳头账户密码 | string|是 |
| img_src | 自定义背景图的url链接 | string | 否 |
| img_ratio | 自定义返回图比例,值为1代表正方形 | int |否 |
| raw | 设置为1,获取Riot接口的原始响应(不画图) | int | 否 |
@@ -163,15 +162,42 @@ https://valorant-api.com/v1/competitivetiers/{competitivetierUuid}
还有一件事!部分皮肤返回结果中,是不带皮肤的图片的(我真的不理解为什么会这样)这也需要你遍历本地找皮肤图片!
+### 3.2 login
+
+该接口用于登录,后台将会根据account将用户的登录信息缓存到内存中
+
+~~~
+https://val.musnow.top/api/v2/login
+~~~
+
+请求方法:`POST`
+
+速率限制:`10r/m`
+
+| body参数 | 说明 | 参数类型 |是否必填 |
+| ---------- | --------------------- | -------- | -------- |
+| token | API token | string|是 |
+| account | 拳头账户 | string |是 |
+| passwd | 拳头账户密码 | string |是 |
+
+返回示例(登陆成功)
+```json
+{"code": 0,"info": "登录成功!", "message": "auth success"}
+```
+返回示例(需要邮箱验证)
+
+```json
+{"code": 0, "info": "2fa用户,请使用/tfa接口提供邮箱验证码", "message": "need provide email verify code"}
+```
-### 3.2 tfa
+### 3.3 tfa
此接口用于两步验证,适用于开启了邮箱验证的用户;
您需要先请求 `/shop-url` 接口,在用户获取到验证码后,再请求本接口;若在10min内没有收到 `/tfa` 接口请求,后台会以**邮箱验证超时**关闭该账户的会话。
~~~
-https://val.musnow.top/api/tfa
+https://val.musnow.top/api/v2/tfa
~~~
请求方法:`POST`
@@ -187,15 +213,10 @@ https://val.musnow.top/api/tfa
返回示例
~~~json
-{
- "code": 0,
- "message": "email verify code post success,wait for shop img return",
- "info": "两步验证码获取成功,请等待主接口返回",
- "vcode": 114514
-}
+{ "code": 0, "message": "2fa auth success", "info": "2fa用户登录成功!"}
~~~
-### 3.3 shop-draw
+### 3.4 shop-draw
这个接口更加适合在本地管理用户的登录信息,本地调用riot api获取用户`商店皮肤/vp/rp`后,再调用此接口,直接返回图片url
@@ -239,6 +260,35 @@ vp/rp只有16-9的图片需要,如果设置了`img_ratio`为`'1'`,则无需
}
~~~
+### 3.4 shop-cmt
+
+该接口用于更新leancloud数据库中的ShopCmt,该数据需要在 8am 并发进行修改。leancloud本身并不提供线程安全处理,就此将所有需要修改ShopCmt的操作统一到本端进行
+
+请求方法:`POST`
+
+| params参数 | 说明 | 参数类型 |是否必填 |
+| ---------- | --------------------- | -------- | -------- |
+| token | API token | string |是 |
+| best | 当日最好用户的商店信息 | json |是 |
+| worse | 当日最差用户的商店信息 | json | 是 |
+| platform | 来源平台 | string | 是 |
+
+best/worse应该包含如下字段,其中`user_id`如果么有可以留空(但是不要少这个字段),rating为当前商店4个皮肤的平均分(如一个皮肤么有评分,则不计入平均分计算)
+
+```json
+{
+ "user_id": "用户id",
+ "rating": 97.0,
+ "list_shop": []
+}
+```
+返回示例
+
+```json
+{"code": 0, "info": "ShopCmp更新成功", "message": true}
+```
+
+
## 4.Python示例代码
### 示例代码1:shop
@@ -246,7 +296,7 @@ vp/rp只有16-9的图片需要,如果设置了`img_ratio`为`'1'`,则无需
~~~python
import requests
-url = "https://val.musnow.top/api/shop"
+url = "https://val.musnow.top/api/v2/shop"
params = {
"token":"api-token",
"account": "拳头账户",
@@ -279,7 +329,7 @@ return res.json()
```python
def ApiRq2(list_shop:list,background='',img_ratio='0'):
- url = "https://val.musnow.top/api/shop-draw"
+ url = "https://val.musnow.top/api/v2/shop-draw"
params = {
"token":"api-token",
"list_shop": list_shop,
@@ -316,4 +366,49 @@ time: 3.9116134020000572
{'code': 0, 'info': '商店图片获取成功', 'message': 'https://img.kookapp.cn/attachments/2023-02/06/xgbRjMQeLQ0rs0rs.png'}
time: 3.822338727999977
{'code': 0, 'info': '商店图片获取成功', 'message': 'https://img.kookapp.cn/attachments/2023-02/06/xgbRjMQeLQ0rs0rs.png'}
+```
+
+### 示例代码3:shop-cmp
+
+```python
+def ApiRq3(best,worse,platform):
+ url = "https://val.musnow.top/api/v2/shop-cmp"
+ params = {
+ "token":"api-token",
+ "best":best,
+ "worse":worse,
+ "platform":platform
+ }
+ res = requests.post(url,json=params) # 请求api
+ print(res)
+ return res.json()
+
+# 调用
+ret = ApiRq3({
+ "user_id": "这是一个测试用例",
+ "rating": 100.0,
+ "list_shop": [
+ "c9678d8c-4327-f397-b0ec-dca3c3d6fb15",
+ "901425cd-405a-d189-3516-ba954965e559",
+ "9f6e4612-433b-aea9-1683-3db7aee90848",
+ "4845a7ab-4120-ae1c-aec1-9e915a7424b1"
+ ]
+ },{
+ "user_id": "这是一个测试用例",
+ "rating": 20.0,
+ "list_shop": [
+ "155ba654-4afa-1029-9e71-e0b6962d5410",
+ "68ee5c6c-4424-e95a-f46f-c08ec2dfeb97",
+ "353c1e5f-4258-c49a-c0d6-319ad33bffea",
+ "e57317ac-4a93-50a9-30e9-93a098513fa9"
+ ]
+ },'qqchannel')
+print(ret)
+```
+
+结果
+
+```
+
+{'code': 0, 'info': 'ShopCmp更新成功', 'message': True}
```
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 373313c..d3e54c7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,9 @@
aiofiles==23.1.0
aiohttp==3.8.1
-khl.py==0.3.7
+khl.py==0.3.15
leancloud==2.9.12
pandas==1.5.2
Pillow==9.4.0
psutil==5.9.4
requests==2.28.1
-riot-auth @ git+https://github.com/floxay/python-riot-auth.git@e70f76002728b99005baccd6fe3157c03d4d9f02
zhconv==1.4.3