上传代码和配置文件

This commit is contained in:
lxbpxylps@126.com 2021-10-07 21:39:01 +08:00
parent 2a6c82b1eb
commit bab9298511
31 changed files with 1589 additions and 0 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
ENVIRONMENT=prod

4
.env.dev Normal file
View File

@ -0,0 +1,4 @@
HOST=0.0.0.0
PORT=4399
DEBUG=true
COMMAND_START=["#"]

4
.env.prod Normal file
View File

@ -0,0 +1,4 @@
HOST=0.0.0.0
PORT=4399
DEBUG=false
COMMAND_START=["#"]

25
bot.py Normal file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import nonebot
from nonebot import logger
from nonebot.adapters.cqhttp import Bot as CQHTTPBot
# 若 data 文件夹不存在则创建
if os.path.exists('data') == False:
os.mkdir('data')
# dev 环境下监控 src config 文件夹变动
nonebot.init(fastapi_reload_dirs=['src', 'config'])
logger.add("./logs/{time:YYYY-MM-DD}.log", rotation="0:00")
app = nonebot.get_asgi()
driver = nonebot.get_driver()
driver.register_adapter("cqhttp", CQHTTPBot)
nonebot.load_from_toml("pyproject.toml")

View File

@ -0,0 +1,5 @@
{
"enable": false,
"group": [],
"liveroom": []
}

40
config/cmd_alias.json Normal file
View File

@ -0,0 +1,40 @@
{
"help": {
"cmd": "帮助",
"aliases": []
},
"bind_qq": {
"cmd": "绑定",
"aliases": [
"绑定账号"
]
},
"call_admin": {
"cmd": "呼叫管理员",
"aliases": []
},
"get_invitation": {
"cmd": "邀请码",
"aliases": []
},
"issue_cmd": {
"cmd": "命令",
"aliases": []
},
"query_online": {
"cmd": "在线人数",
"aliases": []
},
"say_mc_msg": {
"cmd": "服务器",
"aliases": []
},
"tell_mc_msg": {
"cmd": "私聊",
"aliases": []
},
"welcome": {
"cmd": "欢迎",
"aliases": []
}
}

58
config/cmd_register.json Normal file
View File

@ -0,0 +1,58 @@
[
{
"cmd": "list",
"aliases": [
"在线列表"
],
"no_arg": true,
"num": 1,
"wait_time": 1,
"server_tag": "主服",
"allow_member": [],
"permission": "ALL"
},
{
"cmd": "tps",
"aliases": [
"运行状态"
],
"no_arg": true,
"num": 1,
"wait_time": 1,
"server_tag": "主服",
"allow_member": [],
"permission": "ADMIN"
},
{
"cmd": "op",
"aliases": [],
"no_arg": false,
"num": 1,
"wait_time": 1,
"server_tag": "主服",
"allow_member": [],
"permission": "OP"
},
{
"cmd": "deop",
"aliases": [],
"no_arg": false,
"num": 1,
"wait_time": 1,
"server_tag": "主服",
"allow_member": [],
"permission": "OP"
},
{
"cmd": "lp editor",
"aliases": [
"权限编辑"
],
"no_arg": true,
"num": 3,
"wait_time": 5,
"server_tag": "主服",
"allow_member": [],
"permission": "OP"
}
]

View File

@ -0,0 +1,11 @@
{
"enable": false,
"blessing_skin_server_mysql": {
"host": "127.0.0.1",
"port": 3306,
"user": "skin",
"password": "",
"db": "skin"
},
"initial_chance": 0
}

5
config/group.json Normal file
View File

@ -0,0 +1,5 @@
{
"main_group": 123456789,
"op_user": [],
"admin_user": []
}

11
config/mc_event.json Normal file
View File

@ -0,0 +1,11 @@
{
"enable": {
"server_start": true,
"server_stop": true,
"player_join": true,
"player_advancement": true,
"player_chat": true,
"player_quit": true,
"player_quit_private": true
}
}

13
config/mc_server.json Normal file
View File

@ -0,0 +1,13 @@
{
"main_server_tag": "主服",
"server": [
{
"tag": "主服",
"url": "http://127.0.0.1:8520"
},
{
"tag": "游戏服",
"url": "http://192.168.1.2:8520"
}
]
}

67
config/text.json Normal file
View File

@ -0,0 +1,67 @@
{
"not_enable": "此功能未开启!",
"bilibililive_checker": {
"message": "主播<name>开播啦!\n房间标题<title>\n直播分区<area>\n快去<url>围观吧!\n"
},
"bind_qq": {
"help": "#绑定 ID | 将游戏 ID 和 QQ 号绑定",
"format_error": "发送格式错误!\n发送格式#绑定 ID",
"not_bind_msg_in_game": "§4<player>看起来您尚未将游戏账号和QQ号绑定请在群内使用 #绑定 <player> 绑定您的账号\n如果您对此消息感到疑惑请联系管理员",
"not_bind_when_send_msg": "请先通过 #绑定 ID 绑定您的游戏账号!",
"already_bind": "您已经绑定过账号!如果您对此感到疑惑,请联系管理员",
"player_not_exist": "您要绑定的玩家不存在!请确认曾登录过以及输入正确",
"success": "绑定成功!"
},
"call_admin": {
"help": "#呼叫管理员 内容 | 向管理员发送消息",
"format_error": "发送格式错误!\n发送格式#呼叫管理员 内容"
},
"cmd_register": {
"help": "#在线排行 | 查询服务器在线排行\n#tps | 查询服务器 TPS",
"no_permission": "您没有向服务器发送此命令的权限!",
"extra_arg": "此命令不能添加参数!",
"answer": "已执行!\n<res>"
},
"get_invitation": {
"help": "#邀请码 | 索取皮肤站邀请码",
"get_msg": "您的邀请码为:<code>",
"no_chance": "您已耗尽邀请码次数!请联系管理员"
},
"help": {
"help": "#帮助 | 查看机器人帮助"
},
"issue_cmd": {
"no_permission": "您没有向服务器发送命令的权限!",
"format_error": "发送格式错误!\n发送格式#命令 命令,回传行数,等待执行时间,服务器tag",
"server_tag_not_exist": "服务器不存在!",
"answer": "已执行!\n<res>"
},
"mc_event": {
"server_start": "<tag>已开启,用时<time>s",
"server_stop": "<tag>已关闭",
"player_join": "<player>加入了<tag>",
"player_advancement": "<player>在<tag>中取得了进度[<advancement>]",
"player_chat": "<tag>中的<player>:<message>",
"player_quit": "<player>退出了<tag>",
"player_quit_private": "你退出了<tag>,请检查是否为掉线"
},
"query_online": {
"help": "#在线人数 | 查询服务器在线人数",
"no_player": "当前<tag>无人在线",
"list_player": "<tag>当前有<num>人在线:<list>"
},
"say_mc_msg": {
"help": "#服务器 内容 | 向服务器发送消息",
"format_error": "发送格式错误!\n发送格式#服务器 内容",
"msg_in_game": "§5[QQ] §f<bind_player> <msg>"
},
"tell_mc_msg": {
"help": "#私聊 ID 内容 | 向服务器内玩家私发消息",
"format_error": "发送格式错误!\n发送格式#私聊 ID 内容",
"msg_in_game": "§5[QQ] §f<bind_player> 向你私聊消息:<msg>"
},
"welcome": {
"help": "#欢迎 @新人 | 欢迎新人",
"message": "欢迎来到服务器!"
}
}

View File

@ -0,0 +1,358 @@
[
{
"en": "Stone Age",
"zh_cn": "石器时代"
},
{
"en": "Getting an Upgrade",
"zh_cn": "获得升级"
},
{
"en": "Acquire Hardware",
"zh_cn": "来硬的"
},
{
"en": "Suit Up",
"zh_cn": "整装上阵"
},
{
"en": "Hot Stuff",
"zh_cn": "热腾腾的"
},
{
"en": "Isn't It Iron Pick",
"zh_cn": "这不是铁镐么"
},
{
"en": "Not Today, Thank You",
"zh_cn": "不吃这套,谢谢"
},
{
"en": "Ice Bucket Challenge",
"zh_cn": "冰桶挑战"
},
{
"en": "Diamonds!",
"zh_cn": "钻石!"
},
{
"en": "We Need to Go Deeper",
"zh_cn": "勇往直下"
},
{
"en": "Cover Me With Diamonds",
"zh_cn": "钻石护体"
},
{
"en": "Enchanter",
"zh_cn": "附魔师"
},
{
"en": "Zombie Doctor",
"zh_cn": "僵尸科医生"
},
{
"en": "Eye Spy",
"zh_cn": "隔墙有眼"
},
{
"en": "The End?",
"zh_cn": "结束了?"
},
{
"en": "Nether",
"zh_cn": "下界"
},
{
"en": "Return to Sender",
"zh_cn": "见鬼去吧"
},
{
"en": "Those Were the Days",
"zh_cn": "光辉岁月"
},
{
"en": "Hidden in the Depths",
"zh_cn": "深藏不露"
},
{
"en": "Subspace Bubble",
"zh_cn": "曲速泡"
},
{
"en": "A Terrible Fortress",
"zh_cn": "阴森的要塞"
},
{
"en": "Who is Cutting Onions?",
"zh_cn": "谁在切洋葱?"
},
{
"en": "Oh Shiny",
"zh_cn": "金光闪闪"
},
{
"en": "This Boat Has Legs",
"zh_cn": "画船添足"
},
{
"en": "Uneasy Alliance",
"zh_cn": "脆弱的同盟"
},
{
"en": "War Pigs",
"zh_cn": "战猪"
},
{
"en": "Country Lode, Take Me Home",
"zh_cn": "天涯共此石"
},
{
"en": "Cover Me in Debris",
"zh_cn": "残骸裹身"
},
{
"en": "Spooky Scary Skeleton",
"zh_cn": "惊悚恐怖骷髅头"
},
{
"en": "Into Fire",
"zh_cn": "与火共舞"
},
{
"en": "Not Quite \"Nine\" Lives",
"zh_cn": "锚没有九条命"
},
{
"en": "Hot Tourist Destinations",
"zh_cn": "热门景点"
},
{
"en": "Withering Heights",
"zh_cn": "凋零山庄"
},
{
"en": "Local Brewery",
"zh_cn": "本地酿造厂"
},
{
"en": "Bring Home the Beacon",
"zh_cn": "带信标回家"
},
{
"en": "A Furious Cocktail",
"zh_cn": "狂乱的鸡尾酒"
},
{
"en": "Beaconator",
"zh_cn": "信标工程师"
},
{
"en": "How Did We Get Here?",
"zh_cn": "为什么会变成这样呢?"
},
{
"en": "The End",
"zh_cn": "末地"
},
{
"en": "Free the End",
"zh_cn": "解放末地"
},
{
"en": "The Next Generation",
"zh_cn": "下一世代"
},
{
"en": "Remote Getaway",
"zh_cn": "远程折跃"
},
{
"en": "The End... Again...",
"zh_cn": "结束了…再一次…"
},
{
"en": "You Need a Mint",
"zh_cn": "你需要来点薄荷糖"
},
{
"en": "The City at the End of the Game",
"zh_cn": "在游戏尽头的城市"
},
{
"en": "Sky's the Limit",
"zh_cn": "天空即为极限"
},
{
"en": "Great View From Up Here",
"zh_cn": "这上面的风景不错"
},
{
"en": "Adventure",
"zh_cn": "冒险"
},
{
"en": "Voluntary Exile",
"zh_cn": "自我放逐"
},
{
"en": "Is It a Bird?",
"zh_cn": "那是鸟吗?"
},
{
"en": "Monster Hunter",
"zh_cn": "怪物猎人"
},
{
"en": "What a Deal!",
"zh_cn": "成交!"
},
{
"en": "Sticky Situation",
"zh_cn": "胶着状态"
},
{
"en": "Ol' Betsy",
"zh_cn": "扣下悬刀"
},
{
"en": "Surge Protector",
"zh_cn": "电涌保护器"
},
{
"en": "Sweet dreams",
"zh_cn": "甜蜜的梦"
},
{
"en": "Hero of the Village",
"zh_cn": "村庄英雄"
},
{
"en": "Is It a Balloon?",
"zh_cn": "那是气球吗?"
},
{
"en": "Throwaway Joke",
"zh_cn": "抖包袱"
},
{
"en": "Take Aim",
"zh_cn": "瞄准目标"
},
{
"en": "Monsters Hunted",
"zh_cn": "资深怪物猎人"
},
{
"en": "Postmortal",
"zh_cn": "超越生死"
},
{
"en": "Hired Help",
"zh_cn": "招募援兵"
},
{
"en": "Two Birds, One Arrow",
"zh_cn": "一箭双雕"
},
{
"en": "Who's the Pillager Now?",
"zh_cn": "现在谁才是掠夺者?"
},
{
"en": "Arbalistic",
"zh_cn": "劲弩手"
},
{
"en": "Adventuring Time",
"zh_cn": "探索的时光"
},
{
"en": "Is It a Plane?",
"zh_cn": "那是飞机吗?"
},
{
"en": "Very Very Frightening",
"zh_cn": "魔女审判"
},
{
"en": "Sniper Duel",
"zh_cn": "狙击手的对决"
},
{
"en": "Bullseye",
"zh_cn": "正中靶心"
},
{
"en": "Husbandry",
"zh_cn": "农牧业"
},
{
"en": "Bee Our Guest",
"zh_cn": "与蜂共舞"
},
{
"en": "The Parrots and the Bats",
"zh_cn": "我从哪儿来?"
},
{
"en": "Whatever Floats Your Goat!",
"zh_cn": "羊帆起航!"
},
{
"en": "Best Friends Forever",
"zh_cn": "永恒的伙伴"
},
{
"en": "Glow and Behold!",
"zh_cn": "眼前一亮!"
},
{
"en": "Fishy Business",
"zh_cn": "腥味十足的生意"
},
{
"en": "Total Beelocation",
"zh_cn": "举巢搬迁"
},
{
"en": "A Seedy Place",
"zh_cn": "开荒垦地"
},
{
"en": "Wax On",
"zh_cn": "涂蜡"
},
{
"en": "Two by Two",
"zh_cn": "成双成对"
},
{
"en": "A Complete Catalogue",
"zh_cn": "百猫全书"
},
{
"en": "Tactical fishing",
"zh_cn": "战术性钓鱼"
},
{
"en": "A Balanced Diet",
"zh_cn": "均衡饮食"
},
{
"en": "Serious Dedication",
"zh_cn": "终极奉献"
},
{
"en": "Wax Off",
"zh_cn": "脱蜡"
},
{
"en": "The Cutest Predator",
"zh_cn": "最萌捕食者"
},
{
"en": "The Healing Power of Friendship!",
"zh_cn": "友谊的治愈力!"
}
]

1
data/bind_qq.json Normal file
View File

@ -0,0 +1 @@
{}

1
data/invitation.json Normal file
View File

@ -0,0 +1 @@
{}

22
pyproject.toml Normal file
View File

@ -0,0 +1,22 @@
[tool.poetry]
name = "AkashicQQ"
version = "0.1.0"
description = "AkashicQQ"
authors = []
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.7"
nonebot2 = "^2.0.0.a1"
nb-cli = "^0.1.0"
[tool.poetry.dev-dependencies]
nonebot-test = "^0.1.0"
[nonebot.plugins]
plugins = ["nonebot_plugin_apscheduler"]
plugin_dirs = ["src/plugins"]
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

View File

@ -0,0 +1,74 @@
import json
import asyncio
import nonebot
from nonebot.log import logger
from nonebot import require
from nonebot.adapters.cqhttp import Bot, MessageSegment
import httpx
config = json.loads(open('./config/bilibililive_checker.json', 'r').read())
text: str = json.loads(
open('./config/text.json', 'r').read())['bilibililive_checker']['message']
live_status = [False for i in range(len(config['liveroom']))]
scheduler = require("nonebot_plugin_apscheduler").scheduler
@scheduler.scheduled_job("cron", second="*/5")
async def bilibili_checker_handler():
if config['enable'] == False:
return
post_data = {
'uids': config['liveroom']
}
async with httpx.AsyncClient() as client:
res = await client.post(url='https://api.live.bilibili.com/room/v1/Room/get_status_info_by_uids', json=post_data)
res = res.json()
if res['code'] != 0:
return
for i in range(len(config['liveroom'])):
if res['data'][str(config['liveroom'][i])]['live_status'] == 1:
logger.debug(f"uid为{config['liveroom'][i]}的主播正在直播!")
if live_status[i] == False:
live_status[i] = True
at_msg = MessageSegment.at('all') + ''
msg = text.replace('<name>', res['data'][str(config['liveroom'][i])]['uname']).replace(
'<title>', res['data'][str(config['liveroom'][i])]['title']).replace(
'<area>', res['data'][str(config['liveroom'][i])]['area_v2_name']).replace(
'<url>', f"https://live.bilibili.com/{res['data'][str(config['liveroom'][i])]['room_id']}") + \
MessageSegment.image(
res['data'][str(config['liveroom'][i])]['cover_from_user'])
# 获取机器人
while True:
try:
bot: Bot = nonebot.get_bot()
except ValueError:
asyncio.sleep(0)
else:
break
for group_id in config['group']:
# 单独发送 @全体成员,防止次数耗尽导致完全收不到消息
await bot.send_group_msg(group_id=group_id, message=at_msg)
await bot.send_group_msg(group_id=group_id, message=msg)
logger.info(
f"uid为{config['liveroom'][i]}的主播正在直播,发送消息到群{config['group']}")
else:
logger.debug(f"uid为{config['liveroom'][i]}的主播未在直播!")
if live_status[i] == True:
live_status[i] = False

View File

@ -0,0 +1,75 @@
import json
from nonebot import on_command
from nonebot.log import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, MessageEvent
import utils
import prism_api
text: dict = json.loads(open('./config/text.json', 'r').read())['bind_qq']
cmd_set: dict = json.loads(open('./config/cmd_alias.json', 'r').read())['bind_qq']
bind_qq = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@bind_qq.handle()
async def handle_bind_qq(bot: Bot, event: MessageEvent):
# 发送者 user_id
user_id = event.user_id
at_msg = MessageSegment.at(user_id) + '\n'
# 发送者要绑定的玩家
player_to_bind = str(event.message).strip()
# 检测格式
if player_to_bind == '':
await bind_qq.send(at_msg + text['format_error'])
logger.info(f"{user_id}发送格式错误!绑定请求被拒绝")
return
logger.info(f"{user_id}尝试绑定{player_to_bind}")
# 检测是否绑定过
try:
record = json.loads(open('./data/bind_qq.json', 'r').read())
except FileNotFoundError:
record = {}
if str(user_id) in record:
await bind_qq.send(at_msg + text['already_bind'])
logger.debug(f"bind_qq表{record}")
logger.info(f"{user_id}已绑定过!绑定请求被拒绝")
return
# 获取所有登录过的玩家列表,用于检测 ID 是否真实存在
res = []
# 获取所有服务器的 usercache 表
for server in prism_api.config['server']:
prism_res = await prism_api.get(api='/usercache', server_tag=server['tag'])
res += prism_res['data']['usercache']
players = []
for player in res:
players.append(player['name'])
# ID 不存在
if player_to_bind not in players:
await bind_qq.send(at_msg + text['player_not_exist'])
logger.debug(f"usercache表{res}")
logger.info(f"{user_id}要绑定的玩家不存在!绑定请求被拒绝")
return
record[str(user_id)] = player_to_bind
with open('./data/bind_qq.json', 'w') as fp:
fp.write(json.dumps(record))
fp.close()
await bind_qq.send(at_msg + text['success'])
# 通知管理员
await utils.inform_admin(message='绑定了游戏账号:' + player_to_bind, member_user_id=user_id)

View File

@ -0,0 +1,66 @@
import json
from nonebot import on_command
from nonebot.log import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, MessageEvent
import utils
import prism_api
not_bind_when_send_msg: str = json.loads(
open('./config/text.json', 'r').read())['bind_qq']['not_bind_when_send_msg']
text: dict = json.loads(open('./config/text.json', 'r').read())['call_admin']
cmd_set: dict = json.loads(open('./config/cmd_alias.json', 'r').read())['call_admin']
call_admin = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@call_admin.handle()
async def handle_call_admin(bot: Bot, event: MessageEvent):
# 发送者 user_id
user_id = event.user_id
at_msg = MessageSegment.at(user_id) + '\n'
# 内容
msg_to_send = str(event.message).strip()
# 检测格式
if msg_to_send == '':
await call_admin.send(at_msg + text['format_error'])
logger.info(f"{user_id}发送格式错误!呼叫管理员请求被拒绝")
return
logger.info(f"{user_id}尝试呼叫管理员:{msg_to_send}")
# 检查发送者是否绑定账号
try:
record = json.loads(open('./data/bind_qq.json', 'r').read())
except FileNotFoundError:
record = {}
if str(user_id) not in record:
logger.info(f"{user_id}试图向管理员发送消息但未绑定账号,已拒绝")
await call_admin.send(at_msg + not_bind_when_send_msg)
return
# 在 QQ 中通知管理员
await utils.inform_admin(message='向管理员发送消息:' + msg_to_send, member_user_id=user_id)
# 获取群昵称
res = await bot.get_group_member_info(group_id=utils.config['main_group'], user_id=user_id)
if 'card' not in res:
user_card = res['nickname']
else:
user_card = res['card']
# 尝试在游戏内通知管理员
for admin_user_id in utils.config['admin_user']:
if str(admin_user_id) in record:
prism_data = {
'message': f"§5[QQ] §f{user_card} 向管理员发送消息:" + msg_to_send,
'selector': record[str(admin_user_id)]
}
await prism_api.all_server_tellraw(data=prism_data)

View File

@ -0,0 +1,57 @@
import json
from nonebot import on_command
from nonebot.typing import T_State
from nonebot import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, MessageEvent
import utils
import prism_api
config: list = json.loads(open('./config/cmd_register.json', 'r').read())
text: dict = json.loads(open('./config/text.json', 'r').read())['cmd_register']
cmd_list: list = [one_cmd['cmd'] for one_cmd in config]
for one_cmd in config:
cmd_list += one_cmd['aliases']
cmd_register = on_command('cmd_register', aliases=set(cmd_list))
@cmd_register.handle()
async def handle_cmd_register(bot: Bot, event: MessageEvent, state: T_State):
# 发送者 user_card
user_id = event.user_id
at_msg = MessageSegment.at(user_id) + '\n'
for cmd in config:
cmd_and_aliases = [cmd['cmd']]
cmd_and_aliases += cmd['aliases']
# 匹配到命令
if state['_prefix']['command'][0] in cmd_and_aliases:
logger.info(f"{user_id}试图执行命令:{cmd['cmd']}")
# 开始鉴权
if cmd['permission'] == 'ALL' or \
user_id in utils.config['op_user'] or \
(cmd['permission'] == 'ADMIN' and user_id in utils.config['admin_user']) or \
user_id in cmd['allow_member']:
arg = str(event.message).strip()
if arg != '' and cmd['no_arg']:
logger.info(f"{user_id}试图为不可添加参数的命令添加参数")
await cmd_register.send(at_msg + text['extra_arg'])
return
real_cmd = cmd['cmd'] + ' ' + arg
res = await prism_api.server_cmd(cmd=real_cmd, num=cmd['num'], wait_time=cmd['wait_time'], server_tag=cmd['server_tag'])
msg = text['answer'].replace('<res>', res)
await cmd_register.send(at_msg + msg)
logger.info(f"命令执行结果:{res}")
else:
logger.info(f"{user_id}试图执行命令但无权限")
await cmd_register.send(at_msg + text['no_permission'])

View File

@ -0,0 +1,87 @@
import time
import string
import random
import json
from nonebot import on_command
from nonebot import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, MessageEvent
import aiomysql
import utils
config: dict = json.loads(open('./config/get_invitation.json', 'r').read())
text: dict = json.loads(
open('./config/text.json', 'r').read())['get_invitation']
cmd_set: dict = json.loads(open('./config/cmd_alias.json', 'r').read())['get_invitation']
get_invitation = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@get_invitation.handle()
async def handle_get_invitation(bot: Bot, event: MessageEvent):
# 发送者 user_id
user_id = event.user_id
at_msg = MessageSegment.at(user_id) + '\n'
# 鉴定发起者是否有剩余次数
try:
record = json.loads(open('./data/invitation.json', 'r').read())
except FileNotFoundError:
record = {}
# 不存在记录,设置为初始值
if str(user_id) not in record:
if user_id not in utils.config['admin_user']:
record[str(user_id)] = config['initial_chance']
else:
record[str(user_id)] = 1
# 有剩余机会或请求者为管理员,则为其生成邀请码
if record[str(user_id)] > 0 or user_id in utils.config['admin_user']:
conn = await aiomysql.connect(
host=config['blessing_skin_server_mysql']['host'],
port=config['blessing_skin_server_mysql']['port'],
user=config['blessing_skin_server_mysql']['user'],
password=config['blessing_skin_server_mysql']['password'],
db=config['blessing_skin_server_mysql']['db']
)
cur = await conn.cursor()
await cur.execute("SELECT id FROM invitation_codes")
res = await cur.fetchall()
new_id = max(res)[0] + 1
code = f"from{user_id}_" + \
''.join(random.sample(string.ascii_letters + string.digits, 8))
time_stamp = time.strftime(
'%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
await cur.execute(
"INSERT INTO `invitation_codes` (`id`, `code`, `generated_at`, `used_by`, `used_at`) " +
f"VALUES ('{new_id}', '{code}', '{time_stamp}', '0', NULL)"
)
await conn.commit()
conn.close()
msg = text['get_msg'].replace('<code>', code)
await get_invitation.send(at_msg + msg)
# 非管理员,次数减一
if user_id not in utils.config['admin_user']:
record[str(user_id)] -= 1
with open('./data/invitation.json', 'w') as fp:
fp.write(json.dumps(record))
fp.close()
# 通知管理员
await utils.inform_admin(message='索取了邀请码:' + code, member_user_id=user_id)
else:
msg = text['no_chance']
await get_invitation.send(at_msg + msg)
# 通知管理员
await utils.inform_admin(message='试图索取邀请码,但邀请次数已耗尽', member_user_id=user_id)

View File

@ -0,0 +1,30 @@
import json
from nonebot import on_notice
from nonebot.log import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, GroupIncreaseNoticeEvent
import utils
welcome_msg: str = json.loads(
open('./config/text.json', 'r').read())['welcome']['message']
group_increase = on_notice()
@group_increase.handle()
async def handle_group_increase(bot: Bot, event: GroupIncreaseNoticeEvent):
# 入群者 user_id
user_id = event.user_id
at_msg = MessageSegment.at(user_id) + '\n'
# 发送入群欢迎消息
await group_increase.send(at_msg + welcome_msg)
logger.info(f"{user_id}发送入群欢迎消息")
logger.debug(f"欢迎消息:{welcome_msg}")
# 向管理员提示新增成员
user_id = event.user_id
group_id = event.group_id
await utils.inform_admin(message='进入群' + str(group_id), member_user_id=user_id)

View File

@ -0,0 +1,26 @@
import json
from typing import Dict
from nonebot import on_command
from nonebot import logger
from nonebot.adapters.cqhttp import Bot, Message, MessageEvent
text: dict = json.loads(open('./config/text.json', 'r').read())
cmd_set: dict = json.loads(open('./config/cmd_alias.json', 'r').read())['help']
help = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@help.handle()
async def handle_help(bot: Bot, event: MessageEvent):
logger.info('请求帮助')
msg = ''
for key in text:
if type(text[key]) == type({}):
if 'help' in text[key]:
msg += text[key]['help'] + '\n'
await help.send(msg)

View File

@ -0,0 +1,75 @@
import json
from nonebot import on_command
from nonebot.log import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, MessageEvent
import prism_api
op_user: list = json.loads(open('./config/group.json', 'r').read())['op_user']
text: dict = json.loads(open('./config/text.json', 'r').read())['issue_cmd']
cmd_set: dict = json.loads(
open('./config/cmd_alias.json', 'r').read())['issue_cmd']
issue_cmd = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@issue_cmd.handle()
async def handle_issue_cmd(bot: Bot, event: MessageEvent):
# 发送者 user_id
user_id = event.user_id
at_msg = MessageSegment.at(user_id) + '\n'
string = str(event.message).strip()
arg_list = string.split(',')
logger.info(f"{user_id}试图执行命令:{arg_list}")
# 鉴权
if user_id not in op_user:
await issue_cmd.send(at_msg + text['no_permission'])
logger.debug(f"op_user为{op_user}")
logger.info(f"{user_id}试图执行命令但无权限")
return
# 处理命令格式,参数分别为 cmd num wait_time server_tag
cmd = arg_list[0]
if cmd == '':
await issue_cmd.send(at_msg + text['format_error'])
logger.info(f"{user_id}发送格式错误!执行命令请求被拒绝")
return
if len(arg_list) > 1:
num = int(arg_list[1])
else:
num = 1
if len(arg_list) > 2:
wait_time = int(arg_list[2])
else:
wait_time = 1
if len(arg_list) > 3:
server = arg_list[3]
exist_server_tag_list = []
for server in prism_api.config['server']:
exist_server_tag_list.append(server['tag'])
if server not in exist_server_tag_list:
await issue_cmd.send(at_msg + text['server_tag_not_exist'])
logger.info("服务器不存在!执行命令请求被拒绝")
return
else:
server = None
# 发送命令
res = await prism_api.server_cmd(cmd=cmd, num=num, wait_time=wait_time, server_tag=server)
# 回传结果
msg = text['answer'].replace('<res>', res)
await issue_cmd.send(at_msg + msg)
logger.info(f"命令执行结果:{res}")

View File

@ -0,0 +1,192 @@
import json
import asyncio
import nonebot
from nonebot.log import logger
from nonebot.adapters.cqhttp import Bot
from fastapi import Body, FastAPI
import prism_api
config: dict = json.loads(open('./config/mc_event.json', 'r').read())
group_config: dict = json.loads(open('./config/group.json', 'r').read())
text: dict = json.loads(open('./config/text.json', 'r').read())['mc_event']
not_bind_msg_in_game: str = json.loads(
open('./config/text.json', 'r').read())['bind_qq']['not_bind_msg_in_game']
app: FastAPI = nonebot.get_app()
@app.post('/')
async def mc_event_handler(data: dict = Body(...)):
data = data['data']
logger.info(f"收到MC事件: {data}")
while True:
try:
bot: Bot = nonebot.get_bot()
except ValueError:
asyncio.sleep(0)
else:
break
# 处理事件
if data['type'] == 'ServerStart':
await server_start_handler(bot, data)
elif data['type'] == 'ServerStop':
await server_stop_handler(bot, data)
elif data['type'] == 'PlayerJoin':
await player_join_handler(bot, data)
elif data['type'] == 'PlayerAdvancement':
await player_advancement_handler(bot, data)
elif data['type'] == 'PlayerChat':
await player_chat_handler(bot, data)
elif data['type'] == 'PlayerQuit':
await player_quit_handler(bot, data)
return {
"status": 200,
"msg": "success"
}
async def server_start_handler(bot: Bot, data: dict):
if config['enable']['server_start'] == False:
return
message = text['server_start'].replace('<tag>', data['tag']).replace(
'<time>', str(data['start_use_time']))
await bot.send_group_msg(group_id=group_config['main_group'], message=message)
async def server_stop_handler(bot: Bot, data: dict):
if config['enable']['server_stop'] == False:
return
message = text['server_stop'].replace('<tag>', data['tag'])
await bot.send_group_msg(group_id=group_config['main_group'], message=message)
async def player_join_handler(bot: Bot, data: dict):
if config['enable']['player_join'] == False:
return
message = text['player_join'].replace(
'<player>', data['player']).replace('<tag>', data['tag'])
await bot.send_group_msg(group_id=group_config['main_group'], message=message)
prism_data = {
'message': f"§5[{data['tag']}] §f" + message,
'selector': '@a'
}
# 向其他服务器广播消息
for server in prism_api.config['server']:
if data['tag'] != server['tag']:
await prism_api.post(api='/tellraw', data=prism_data, server_tag=server['tag'])
# 检测玩家是否绑定账号
try:
record = json.loads(open('./data/bind_qq.json', 'r').read())
players = list(record.values())
except FileNotFoundError:
players = []
# 玩家未绑定账号
if data['player'] not in players:
prism_data = {
'message': not_bind_msg_in_game.replace('<player>', data['player']),
'selector': data['player']
}
await prism_api.post(api='/tellraw', data=prism_data, server_tag=data['tag'])
logger.info(f"加入服务器{data['tag']}的玩家{data['player']}未绑定账号,已向其发送提示")
async def player_advancement_handler(bot: Bot, data: dict):
if config['enable']['player_advancement'] == False:
return
# 检查成就翻译
try:
tranlation = json.loads(
open('./data/advancement_translation.json', 'r').read())
except FileNotFoundError:
tranlation = {}
for adv in tranlation:
if adv['en'].lower().strip() == data['advancement'].lower().strip():
data['advancement'] = adv['zh_cn']
break
message = text['player_advancement'].replace(
'<player>', data['player']).replace('<advancement>', data['advancement']).replace('<tag>', data['tag'])
await bot.send_group_msg(group_id=group_config['main_group'], message=message)
prism_data = {
'message': f"§5[{data['tag']}] §f" + message,
'selector': '@a'
}
# 向其他服务器广播消息
for server in prism_api.config['server']:
if data['tag'] != server['tag']:
await prism_api.post(api='/tellraw', data=prism_data, server_tag=server['tag'])
async def player_chat_handler(bot: Bot, data: dict):
if config['enable']['player_chat'] == False:
return
message = text['player_chat'].replace(
'<player>', data['player']).replace('<message>', data['message']).replace('<tag>', data['tag'])
await bot.send_group_msg(group_id=group_config['main_group'], message=message)
prism_data = {
'message': f"§5[{data['tag']}] §f" + message,
'selector': '@a'
}
# 向其他服务器广播消息
for server in prism_api.config['server']:
if data['tag'] != server['tag']:
await prism_api.post(api='/tellraw', data=prism_data, server_tag=server['tag'])
async def player_quit_handler(bot: Bot, data: dict):
if config['enable']['player_quit'] == True:
message = text['player_quit'].replace(
'<player>', data['player']).replace('<tag>', data['tag'])
await bot.send_group_msg(group_id=group_config['main_group'], message=message)
prism_data = {
'message': f"§5[{data['tag']}] §f" + message,
'selector': '@a'
}
# 向其他服务器广播消息
for server in prism_api.config['server']:
if data['tag'] != server['tag']:
await prism_api.post(api='/tellraw', data=prism_data, server_tag=server['tag'])
if config['enable']['player_quit_private'] == True:
# 向本人发送消息,提醒下线
try:
record = json.loads(open('./data/bind_qq.json', 'r').read())
except FileNotFoundError:
record = {}
for key in record:
if record[key] == data['player']:
message = text['player_quit_private'].replace(
'<player>', data['player']).replace('<tag>', data['tag'])
await bot.send_private_msg(user_id=int(key), message=message)

View File

@ -0,0 +1,73 @@
import json
import re
from nonebot.log import logger
import httpx
config = json.loads(open('./config/mc_server.json', 'r').read())
async def get(api: str, server_tag: str = None):
if server_tag == None:
server_tag = config['main_server_tag']
for server in config['server']:
if server['tag'] == server_tag:
url = server['url']
async with httpx.AsyncClient() as client:
logger.debug(f"发送prism_api.get{url + api} server={server_tag}")
resp = await client.get(url=url + api, timeout=10)
resp = resp.json()
logger.debug(f"prism_api.get回复{resp}")
return resp
async def post(api: str, data: dict = [], server_tag: str = None):
if server_tag == None:
server_tag = config['main_server_tag']
for server in config['server']:
if server['tag'] == server_tag:
url = server['url']
async with httpx.AsyncClient() as client:
logger.debug(
f"发送prism_api.post{url + api} data={data} server={server_tag}")
resp = await client.post(url=url + api, json=data, timeout=10)
resp = resp.json()
logger.debug(f"prism_api.post回复{resp}")
return resp
async def server_cmd(cmd: str, num: int = 1, wait_time: int = 1, server_tag: str = None):
data = {
'cmd': cmd,
'num': num,
'wait_time': wait_time
}
logger.debug(f"发送prism_api.server_cmddata={data} server={server_tag}")
res = await post(api='/cmd', data=data, server_tag=server_tag)
if res['status'] == 200:
res_str = ''
for string in res['data']['list']:
temp_list = re.findall("]: (.*?)$", string)
if temp_list:
res_str += temp_list[0] + '\n'
logger.debug(f"prism_api.server_cmd回复{res_str}")
return res_str
else:
logger.debug(f"prism_api.server_cmd请求对应服务器未开启游戏返回空值")
return ''
async def all_server_tellraw(data: dict = []):
logger.debug(f"prism_api.all_server_tellraw data={data}")
async with httpx.AsyncClient() as client:
for server in config['server']:
await client.post(url=server['url'] + '/tellraw', json=data, timeout=10)

View File

@ -0,0 +1,37 @@
import json
from nonebot import on_command
from nonebot import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, MessageEvent
import prism_api
text: dict = json.loads(open('./config/text.json', 'r').read())['query_online']
cmd_set: dict = json.loads(open('./config/cmd_alias.json', 'r').read())['query_online']
query_online = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@query_online.handle()
async def handle_query_online(bot: Bot, event: MessageEvent):
for server in prism_api.config['server']:
res = await prism_api.get(api='/list', server_tag=server['tag'])
tag = res['data']['tag']
res = res['data']['player_list']
num = len(res)
if num == 0:
msg = text['no_player'].replace('<tag>', tag)
else:
player_list = ''
for i in range(num):
if i == 0:
player_list += res[i]
else:
player_list += ', ' + res[i]
msg = text['list_player'].replace(
'<num>', str(num)).replace('<list>', player_list).replace('<tag>', tag)
logger.info(f"查询在线人数:{tag} {res}")
await query_online.send(msg)

View File

@ -0,0 +1,51 @@
import json
from nonebot import on_command
from nonebot import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, MessageEvent
import prism_api
not_bind_when_send_msg: str = json.loads(
open('./config/text.json', 'r').read())['bind_qq']['not_bind_when_send_msg']
text: dict = json.loads(open('./config/text.json', 'r').read())['say_mc_msg']
cmd_set: dict = json.loads(open('./config/cmd_alias.json', 'r').read())['say_mc_msg']
say_mc_msg = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@say_mc_msg.handle()
async def handle_say_mc_msg(bot: Bot, event: MessageEvent):
# 发送者 user_id
user_id = event.user_id
at_msg = MessageSegment.at(user_id) + '\n'
# 检查发送者是否绑定账号
try:
record = json.loads(open('./data/bind_qq.json', 'r').read())
except FileNotFoundError:
record = {}
if str(user_id) not in record:
logger.info(f"{user_id}试图向服务器发送消息但未绑定账号,已拒绝")
await say_mc_msg.send(at_msg + not_bind_when_send_msg)
return
user_card = record[str(user_id)]
# 发送消息
msg_to_send = str(event.message).strip()
if msg_to_send == '':
logger.info(f"{user_id}发送格式错误!发送消息请求被拒绝")
await say_mc_msg.send(at_msg + text['format_error'])
return
data = {
'message': text['msg_in_game'].replace('<bind_player>', user_card).replace('<msg>', msg_to_send),
'selector': '@a'
}
await prism_api.all_server_tellraw(data=data)
logger.info(f"{user_id}向服务器发送消息:{msg_to_send}")

View File

@ -0,0 +1,52 @@
import json
from nonebot import on_command
from nonebot import logger
from nonebot.adapters.cqhttp import Bot, MessageSegment, MessageEvent
import prism_api
not_bind_when_send_msg: str = json.loads(
open('./config/text.json', 'r').read())['bind_qq']['not_bind_when_send_msg']
text: dict = json.loads(open('./config/text.json', 'r').read())['tell_mc_msg']
cmd_set: dict = json.loads(open('./config/cmd_alias.json', 'r').read())['tell_mc_msg']
tell_mc_msg = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@tell_mc_msg.handle()
async def handle_tell_mc_msg(bot: Bot, event: MessageEvent):
# 发送者 user_card
user_id = event.user_id
at_msg = MessageSegment.at(user_id) + '\n'
# 检查发送者是否绑定账号
record = json.loads(open('./data/bind_qq.json', 'r').read())
if str(user_id) not in record:
logger.info(f"{user_id}试图向服务器私聊消息但未绑定账号,已拒绝")
await tell_mc_msg.send(at_msg + not_bind_when_send_msg)
return
user_card = record[str(user_id)]
# 发送消息
stripped_arg = str(event.message).strip()
index = stripped_arg.find(' ')
player_id = stripped_arg[0:index]
msg_to_send = (stripped_arg[index + 1:len(stripped_arg)])
if player_id == '' or msg_to_send == '' or index == -1:
logger.info(f"{user_id}发送格式错误!私聊消息请求被拒绝")
await tell_mc_msg.send(at_msg + text['format_error'])
return
data = {
'message': text['msg_in_game'].replace('<bind_player>', user_card).replace('<msg>', msg_to_send),
'selector': player_id
}
await prism_api.all_server_tellraw(data=data)
logger.info(f"{user_id}{player_id}私聊消息:{msg_to_send}")

View File

@ -0,0 +1,40 @@
import json
import asyncio
import nonebot
from nonebot import logger
from nonebot.adapters.cqhttp import Bot
config = json.loads(open('./config/group.json', 'r').read())
async def inform_admin(message: str, member_user_id: int = None):
while True:
try:
bot: Bot = nonebot.get_bot()
except ValueError:
asyncio.sleep(0)
else:
break
# 指定 member_user_id
if member_user_id != None:
# 获取 member 群昵称
res = await bot.get_group_member_info(group_id=config['main_group'], user_id=member_user_id)
if 'card' not in res:
user_card = res['nickname']
else:
user_card = res['card']
for i in range(len(config['admin_user'])):
await bot.send_private_msg(user_id=config['admin_user'][i], message=f"{user_card}({member_user_id}){message}")
logger.info(f"{user_card}({member_user_id}){message}")
else:
for i in range(len(config['admin_user'])):
await bot.send_private_msg(user_id=config['admin_user'][i], message=message)
logger.info(message)

View File

@ -0,0 +1,28 @@
import json
from nonebot import on_command
from nonebot import logger
from nonebot.adapters.cqhttp import Bot, Message, MessageEvent
welcome_msg: str = json.loads(
open('./config/text.json', 'r').read())['welcome']['message']
cmd_set: dict = json.loads(open('./config/cmd_alias.json', 'r').read())['welcome']
welcome = on_command(cmd_set['cmd'], aliases=set(cmd_set['aliases']))
@welcome.handle()
async def handle_welcome(bot: Bot, event: MessageEvent):
arg = str(event.message).strip()
if not arg: # 用户未发送参数
at_msg = ''
else: # 用户发送参数
at_msg = Message(arg + '\n')
logger.info('发送欢迎消息')
logger.debug(f"欢迎消息:{welcome_msg}")
await welcome.send(at_msg + welcome_msg)