mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-02 18:20:01 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79185bd90f | ||
|
|
d695c30988 | ||
|
|
6ff6009a70 | ||
|
|
dadeb4006e | ||
|
|
1f01ba1d10 | ||
|
|
62965fe1df | ||
|
|
e29eb4cce5 | ||
|
|
699791e318 | ||
|
|
d2aae0103d | ||
|
|
ab06e38b7c | ||
|
|
8a0ca3c2e5 | ||
|
|
97317ed2c6 | ||
|
|
1bb9b2cb3f | ||
|
|
7ba129b3bf | ||
|
|
1e2c9ca28a | ||
|
|
c6f37fd05f | ||
|
|
b6b569fff9 | ||
|
|
ac57c016a6 | ||
|
|
28fdd9de95 | ||
|
|
1ec946aaa9 | ||
|
|
d6110e3c6f | ||
|
|
4c5302bd4c | ||
|
|
21ee3d5c3e | ||
|
|
e5c036cee8 | ||
|
|
6f82488af7 | ||
|
|
57a7903c63 | ||
|
|
27b89b333a | ||
|
|
ce2c4e7492 | ||
|
|
cad98a2a33 | ||
|
|
40da48e685 | ||
|
|
1c393e5c3e | ||
|
|
667c143c74 | ||
|
|
bc089c18ce | ||
|
|
24b730c0e2 | ||
|
|
9ed9e9b973 | ||
|
|
5b0027aa3d | ||
|
|
810c5e4e8b | ||
|
|
907534958f | ||
|
|
f08a18ab07 | ||
|
|
40549d5ca7 | ||
|
|
3e67edc506 | ||
|
|
9c56a81f65 | ||
|
|
a9a636c9ae | ||
|
|
98374dcd74 | ||
|
|
10ca6eec91 |
@@ -235,14 +235,74 @@ python bot.py
|
||||
|
||||
|
||||
## 使用Docker
|
||||
__Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||
#### GitHub:[Sakuracio/zhenxun_bot_docker](https://github.com/Sakuracio/zhenxun_bot_docker)
|
||||
#### DockerHub:[hibikier/zhenxun_bot](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
||||
|
||||
|
||||
__Docker 单机版(仅真寻Bot)__
|
||||
**点击下方的 GitHub 徽标查看教程**
|
||||
[](https://github.com/Sakuracio/zhenxun_bot_docker)
|
||||
[](https://hub.docker.com/r/hibikier/zhenxun_bot)
|
||||
__Docker 全量版(包含 真寻Bot PostgreSQL数据库 go-cqhttp webui等)__
|
||||
[](https://github.com/SinKy-Yan/zhenxunbot-docker)
|
||||
[](https://hub.docker.com/r/jyishit/zhenxun_bot)
|
||||
**点击上方的 GitHub 徽标查看教程**
|
||||
PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能无法正常启动全量版容器**
|
||||
|
||||
## 更新
|
||||
|
||||
### 2022/7/24 \[v0.1.6.2]
|
||||
|
||||
* 订阅up动态提供直链
|
||||
|
||||
### 2022/7/23
|
||||
|
||||
* 优化开箱次数判断
|
||||
|
||||
### 2022/7/16
|
||||
|
||||
* cos提供连发命令
|
||||
* 修复B站视频解析中b23解析错误
|
||||
|
||||
### 2022/7/13
|
||||
|
||||
* B站订阅提供配置项`LIVE_MSG_AT_ALL`,`UP_MSG_AT_ALL`:控制UP动态投稿和直播是否AT全体
|
||||
* 修改了Omega图库检测的数据库文件名
|
||||
* game_utils提供了Game类
|
||||
|
||||
### 2022/7/7
|
||||
|
||||
* 微博热搜选择单条热搜时也会检测时效性 [@pull/891](https://github.com/HibiKier/zhenxun_bot/pull/891)
|
||||
|
||||
### 2022/7/4
|
||||
|
||||
* 修复商品未设置限购时无法购买
|
||||
* 修复B站订阅UP动态 [@pull/886](https://github.com/HibiKier/zhenxun_bot/pull/886)
|
||||
* 修复色图命令带tag时配置项`MAX_ONCE_NUM2FORWARD`无法生效
|
||||
|
||||
### 2022/7/3 \[v0.1.6.1]
|
||||
|
||||
* BagUser提供方法`check_props`方法,用于判断用户是否含有该道具并是否使用
|
||||
* 优化商品显示图片,提供限制,限购,折扣提示
|
||||
* 修复图库内图片无法被连续删除的问题 [@pull/879](https://github.com/HibiKier/zhenxun_bot/pull/879)
|
||||
* 色图提供配置项`MAX_ONCE_NUM2FORWARD`:群聊中单次发送图片数量达到指定时使用合并转发
|
||||
* 优化修复了商品修改命令
|
||||
* B站订阅UP动态改为详情页截图
|
||||
|
||||
### 2022/6/28
|
||||
|
||||
* 修复色图插件api修改无法搜索图片 [@pull/866](https://github.com/HibiKier/zhenxun_bot/pull/866)
|
||||
|
||||
### 2022/6/26
|
||||
|
||||
* 替换了bt URL
|
||||
* PIX当使用pid查询图片时,会发送该pid下所有图片
|
||||
* 商店提供了每日购买次数限制
|
||||
|
||||
### 2022/6/24
|
||||
|
||||
* 对WSL虚拟机 代理 添加写法 [@pull/847](https://github.com/HibiKier/zhenxun_bot/pull/847)
|
||||
|
||||
### 2022/6/21
|
||||
|
||||
* update parse_bilibili [@pull/840](https://github.com/HibiKier/zhenxun_bot/pull/840)
|
||||
|
||||
### 2022/6/19 \[v0.1.6.0]
|
||||
|
||||
* 暂时使用hook修复webui中plugins2setting修改时会改变plugins2setting.cmd为字符串
|
||||
@@ -517,7 +577,7 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||
* 修复点歌无法正确发送
|
||||
* 修复我有一个朋友有时文本会包含CQ码
|
||||
* 修复群欢消息被动控制文本未删除 [@pull/124](https://github.com/HibiKier/zhenxun_bot/pull/124)
|
||||
* message_builder.image不再提供参数:abspath
|
||||
* message_builder.image不再提供参数:abspath
|
||||
|
||||
### 2022/2/23
|
||||
|
||||
@@ -654,10 +714,13 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
|
||||
|
||||
__..... 更多更新信息请查看文档__
|
||||
|
||||
|
||||
## Todo
|
||||
- [ ] web管理
|
||||
|
||||
## 爱发电
|
||||
|
||||
<img width="365px" height="450px" src="https://user-images.githubusercontent.com/45528451/175059389-cfeb8174-fa07-4939-80ab-a039087a50f6.png">
|
||||
|
||||
## 感谢
|
||||
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
|
||||
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp的golang实现,轻量、原生跨平台.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__: v0.1.6.0
|
||||
__version__: v0.1.6.2
|
||||
|
||||
@@ -6,7 +6,6 @@ from models.group_info import GroupInfo
|
||||
from models.friend_user import FriendUser
|
||||
from nonebot.adapters.onebot.v11 import ActionFailed
|
||||
from configs.config import NICKNAME, Config
|
||||
from utils.manager import group_manager
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
@@ -42,7 +41,7 @@ Config.add_plugin_config(
|
||||
)
|
||||
|
||||
|
||||
cx = on_message(priority=9, block=False)
|
||||
cx = on_message(priority=9999, block=False, rule=lambda: False)
|
||||
|
||||
|
||||
# 早上好
|
||||
|
||||
@@ -25,7 +25,7 @@ __plugin_configs__ = {
|
||||
|
||||
friend_req = on_request(priority=5, block=True)
|
||||
group_req = on_request(priority=5, block=True)
|
||||
x = on_message(priority=999, block=False)
|
||||
x = on_message(priority=999, block=False, rule=lambda: False)
|
||||
|
||||
exists_data = {"private": {}, "group": {}}
|
||||
|
||||
|
||||
@@ -112,6 +112,14 @@ async def _():
|
||||
"ALTER TABLE chat_history ADD plain_text Text;",
|
||||
"chat_history"
|
||||
), # 新增纯文本
|
||||
(
|
||||
"ALTER TABLE goods_info ADD daily_limit Integer DEFAULT 0;",
|
||||
"goods_info"
|
||||
), # 新增纯文本
|
||||
(
|
||||
"ALTER TABLE goods_info ADD daily_purchase_limit Json DEFAULT '{}';",
|
||||
"goods_info"
|
||||
), # 新增纯文本
|
||||
]
|
||||
for sql in sql_str:
|
||||
try:
|
||||
|
||||
@@ -77,7 +77,11 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||
await BagUser.get_gold(event.user_id, event.group_id)
|
||||
) < goods.goods_price * num * goods.goods_discount:
|
||||
await buy.finish("您的金币好像不太够哦", at_sender=True)
|
||||
flag, n = await GoodsInfo.check_user_daily_purchase(goods, event.user_id, event.group_id, num)
|
||||
if flag:
|
||||
await buy.finish(f"该次购买将超过每日次数限制,目前该道具还可以购买{n}次哦", at_sender=True)
|
||||
if await BagUser.buy_property(event.user_id, event.group_id, goods, num):
|
||||
await GoodsInfo.add_user_daily_purchase(goods, event.user_id, event.group_id, num)
|
||||
await buy.send(
|
||||
f"花费 {goods.goods_price * num * goods.goods_discount} 金币购买 {goods.goods_name} ×{num} 成功!",
|
||||
at_sender=True,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info
|
||||
from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info, GoodsInfo
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent, Message
|
||||
from nonebot import on_command
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.message_builder import image
|
||||
from nonebot.permission import SUPERUSER
|
||||
from utils.utils import is_number
|
||||
from utils.utils import is_number, scheduler
|
||||
from nonebot.params import CommandArg
|
||||
from nonebot.plugin import export
|
||||
from services.log import logger
|
||||
@@ -128,6 +128,18 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
|
||||
await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功")
|
||||
else:
|
||||
await shop_update_goods.send(f"修改商品 {name} 失败了...", at_sender=True)
|
||||
await shop_update_goods.send(name, at_sender=True)
|
||||
logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败")
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
"cron",
|
||||
hour=0,
|
||||
minute=0,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
await GoodsInfo.reset_daily_purchase()
|
||||
logger.info("商品每日限购次数重置成功...")
|
||||
except Exception as e:
|
||||
logger.error(f"商品每日限购次数重置发生错误 {type(e)}:{e}")
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from PIL import Image
|
||||
|
||||
from models.goods_info import GoodsInfo
|
||||
from utils.image_utils import BuildImage
|
||||
from models.sign_group_user import SignGroupUser
|
||||
from utils.utils import is_number
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from typing import Optional, Union
|
||||
from typing import Optional, Union, Tuple
|
||||
from configs.config import Config
|
||||
from nonebot import Driver
|
||||
from nonebot.plugin import require
|
||||
@@ -32,6 +34,7 @@ async def init_default_shop_goods():
|
||||
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
|
||||
),
|
||||
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
|
||||
daily_limit=(10, 20, 30),
|
||||
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
|
||||
)
|
||||
async def sign_card(user_id: int, group_id: int, prob: float):
|
||||
@@ -62,8 +65,9 @@ async def create_shop_help() -> str:
|
||||
_list.append(goods)
|
||||
A = BuildImage(1000, h, color="#f9f6f2")
|
||||
current_h = 0
|
||||
total_n = 0
|
||||
for goods in _list:
|
||||
bk = BuildImage(700, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
|
||||
bk = BuildImage(1180, 80, font_size=15, color="#f9f6f2", font="CJGaoDeGuo.otf")
|
||||
goods_image = BuildImage(
|
||||
600, 80, font_size=20, color="#a29ad6", font="CJGaoDeGuo.otf"
|
||||
)
|
||||
@@ -75,16 +79,27 @@ async def create_shop_help() -> str:
|
||||
)
|
||||
await name_image.aline((380, -5, 280, 45), "#a29ad6", 5)
|
||||
await name_image.atext((390, 0), "售价:", center_type="by_height")
|
||||
await name_image.atext(
|
||||
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
|
||||
)
|
||||
if goods.goods_discount != 1:
|
||||
discount_price = int(goods.goods_discount * goods.goods_price)
|
||||
old_price_image = BuildImage(0, 0, plain_text=str(goods.goods_price), font_color=(194, 194, 194), font="CJGaoDeGuo.otf", font_size=15)
|
||||
await old_price_image.aline((0, int(old_price_image.h / 2), old_price_image.w + 1, int(old_price_image.h / 2)), (0, 0, 0))
|
||||
await name_image.apaste(
|
||||
old_price_image, (440, 0), True
|
||||
)
|
||||
await name_image.atext(
|
||||
(440, 15), str(discount_price), (255, 255, 255)
|
||||
)
|
||||
else:
|
||||
await name_image.atext(
|
||||
(440, 0), str(goods.goods_price), (255, 255, 255), center_type="by_height"
|
||||
)
|
||||
await name_image.atext(
|
||||
(
|
||||
440
|
||||
+ BuildImage(0, 0, plain_text=str(goods.goods_price), font_size=25).w,
|
||||
0,
|
||||
),
|
||||
" 金币",
|
||||
f" 金币",
|
||||
center_type="by_height",
|
||||
)
|
||||
await name_image.acircle_corner(5)
|
||||
@@ -92,15 +107,18 @@ async def create_shop_help() -> str:
|
||||
await goods_image.atext((15, 50), f"简介:{goods.goods_description}")
|
||||
await goods_image.acircle_corner(20)
|
||||
await bk.apaste(goods_image, alpha=True)
|
||||
n = 0
|
||||
_w = 550
|
||||
# 添加限时图标和时间
|
||||
if goods.goods_limit_time > 0:
|
||||
n += 140
|
||||
_limit_time_logo = BuildImage(
|
||||
40, 40, background=f"{IMAGE_PATH}/other/time.png"
|
||||
)
|
||||
await bk.apaste(_limit_time_logo, (600, 0), True)
|
||||
await bk.apaste(_limit_time_logo, (_w + 50, 0), True)
|
||||
await bk.apaste(
|
||||
BuildImage(0, 0, plain_text="限时!", font_size=23, font="CJGaoDeGuo.otf"),
|
||||
(640, 10),
|
||||
(_w + 90, 10),
|
||||
True,
|
||||
)
|
||||
limit_time = time.strftime(
|
||||
@@ -109,28 +127,66 @@ async def create_shop_help() -> str:
|
||||
y_m_d = limit_time[0]
|
||||
_h_m = limit_time[1].split(":")
|
||||
h_m = _h_m[0] + "时 " + _h_m[1] + "分"
|
||||
await bk.atext((605, 38), str(y_m_d))
|
||||
await bk.atext((615, 57), str(h_m))
|
||||
await bk.aline((550, -1, 710, -1), "#a29ad6", 5)
|
||||
await bk.aline((550, 80, 710, 80), "#a29ad6", 5)
|
||||
await bk.atext((_w + 55, 38), str(y_m_d))
|
||||
await bk.atext((_w + 65, 57), str(h_m))
|
||||
_w += 140
|
||||
if goods.goods_discount != 1:
|
||||
n += 140
|
||||
_discount_logo = BuildImage(30, 30, background=f"{IMAGE_PATH}/other/discount.png")
|
||||
await bk.apaste(_discount_logo, (_w + 50, 10), True)
|
||||
await bk.apaste(
|
||||
BuildImage(0, 0, plain_text="折扣!", font_size=23, font="CJGaoDeGuo.otf"),
|
||||
(_w + 90, 15),
|
||||
True,
|
||||
)
|
||||
await bk.apaste(
|
||||
BuildImage(0, 0, plain_text=f"{10 * goods.goods_discount:.1f} 折", font_size=30, font="CJGaoDeGuo.otf", font_color=(85, 156, 75)),
|
||||
(_w + 50, 44),
|
||||
True,
|
||||
)
|
||||
_w += 140
|
||||
if goods.daily_limit != 0:
|
||||
n += 140
|
||||
_daily_limit_logo = BuildImage(35, 35, background=f"{IMAGE_PATH}/other/daily_limit.png")
|
||||
await bk.apaste(_daily_limit_logo, (_w + 50, 10), True)
|
||||
await bk.apaste(
|
||||
BuildImage(0, 0, plain_text="限购!", font_size=23, font="CJGaoDeGuo.otf"),
|
||||
(_w + 90, 20),
|
||||
True,
|
||||
)
|
||||
await bk.apaste(
|
||||
BuildImage(0, 0, plain_text=f"{goods.daily_limit}", font_size=30, font="CJGaoDeGuo.otf"),
|
||||
(_w + 72, 45),
|
||||
True,
|
||||
)
|
||||
if total_n < n:
|
||||
total_n = n
|
||||
if n:
|
||||
await bk.aline((550, -1, 550 + n, -1), "#a29ad6", 5)
|
||||
await bk.aline((550, 80, 550 + n, 80), "#a29ad6", 5)
|
||||
|
||||
# 添加限时图标和时间
|
||||
idx += 1
|
||||
await A.apaste(bk, (0, current_h), True)
|
||||
current_h += 90
|
||||
w = 1000
|
||||
w = 850
|
||||
if total_n:
|
||||
w += total_n
|
||||
h = A.h + 230 + 100
|
||||
h = 1000 if h < 1000 else h
|
||||
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
|
||||
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
|
||||
shop.paste(A, (20, 230))
|
||||
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan.png")
|
||||
zx_img = BuildImage(0, 0, background=f"{IMAGE_PATH}/zhenxun/toukan_3.png")
|
||||
zx_img.transpose(Image.FLIP_LEFT_RIGHT)
|
||||
zx_img.replace_color_tran(((240, 240, 240), (255, 255, 255)), (249, 246, 242))
|
||||
await shop.apaste(zx_img, (780, 100))
|
||||
await shop.apaste(zx_img, (0, 100))
|
||||
shop.paste(A, (20 + zx_img.w, 230))
|
||||
await shop.apaste(shop_logo, (450, 30), True)
|
||||
shop.text(
|
||||
(int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2), 170),
|
||||
"注【通过 序号 或者 商品名称 购买】",
|
||||
)
|
||||
shop.text((20, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
|
||||
shop.text((20 + zx_img.w, h - 100), "神秘药水\t\t售价:9999999金币\n\t\t鬼知道会有什么效果~")
|
||||
return shop.pic2bs4()
|
||||
|
||||
|
||||
@@ -140,6 +196,7 @@ async def register_goods(
|
||||
des: str,
|
||||
discount: Optional[float] = 1,
|
||||
limit_time: Optional[int] = 0,
|
||||
daily_limit: Optional[int] = 0,
|
||||
) -> bool:
|
||||
"""
|
||||
添加商品
|
||||
@@ -151,6 +208,7 @@ async def register_goods(
|
||||
:param des: 商品简介
|
||||
:param discount: 商品折扣
|
||||
:param limit_time: 商品限时销售时间,单位为小时
|
||||
:param daily_limit: 每日购买次数限制
|
||||
:return: 是否添加成功
|
||||
"""
|
||||
if not await GoodsInfo.get_goods_info(name):
|
||||
@@ -162,7 +220,7 @@ async def register_goods(
|
||||
else 0
|
||||
)
|
||||
return await GoodsInfo.add_goods(
|
||||
name, int(price), des, float(discount), limit_time
|
||||
name, int(price), des, float(discount), limit_time, daily_limit
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -192,7 +250,7 @@ async def delete_goods(name: str, id_: int) -> "str, str, int":
|
||||
|
||||
|
||||
# 更新商品信息
|
||||
async def update_goods(**kwargs) -> "str, str, int":
|
||||
async def update_goods(**kwargs) -> Tuple[bool, str, str]:
|
||||
"""
|
||||
更新商品信息
|
||||
:param kwargs: kwargs
|
||||
@@ -202,17 +260,18 @@ async def update_goods(**kwargs) -> "str, str, int":
|
||||
goods_lst = await GoodsInfo.get_all_goods()
|
||||
if is_number(kwargs["name"]):
|
||||
if int(kwargs["name"]) < 1 or int(kwargs["name"]) > len(goods_lst):
|
||||
return "序号错误,没有该序号的商品...", "", 999
|
||||
return False, "序号错误,没有该序号的商品...", ""
|
||||
goods = goods_lst[int(kwargs["name"]) - 1]
|
||||
else:
|
||||
goods = await GoodsInfo.get_goods_info(kwargs["name"])
|
||||
if not goods:
|
||||
return "名称错误,没有该名称的商品...", "", 999
|
||||
name = goods.goods_name
|
||||
return False, "名称错误,没有该名称的商品...", ""
|
||||
name: str = goods.goods_name
|
||||
price = goods.goods_price
|
||||
des = goods.goods_description
|
||||
discount = goods.goods_discount
|
||||
limit_time = goods.goods_limit_time
|
||||
daily_limit = goods.daily_limit
|
||||
new_time = 0
|
||||
tmp = ""
|
||||
if kwargs.get("price"):
|
||||
@@ -229,24 +288,25 @@ async def update_goods(**kwargs) -> "str, str, int":
|
||||
new_time = time.strftime(
|
||||
"%Y-%m-%d %H:%M:%S",
|
||||
time.localtime(time.time() + kwargs["limit_time"] * 60 * 60),
|
||||
)
|
||||
tmp += f"限时至: {new_time}\n"
|
||||
) if kwargs["limit_time"] != 0 else 0
|
||||
tmp += f"限时至: {new_time}\n" if new_time else "取消了限时\n"
|
||||
limit_time = kwargs["limit_time"]
|
||||
return (
|
||||
await GoodsInfo.update_goods(
|
||||
name,
|
||||
int(price),
|
||||
des,
|
||||
float(discount),
|
||||
int(
|
||||
time.time() + limit_time * 60 * 60
|
||||
if limit_time != 0 and new_time
|
||||
else 0
|
||||
),
|
||||
),
|
||||
if kwargs.get("daily_limit"):
|
||||
tmp += f'每日购买限制:{daily_limit} --> {kwargs["daily_limit"]}\n' if daily_limit else "取消了购买限制\n"
|
||||
daily_limit = int(kwargs["daily_limit"])
|
||||
await GoodsInfo.update_goods(
|
||||
name,
|
||||
tmp[:-1],
|
||||
int(price),
|
||||
des,
|
||||
float(discount),
|
||||
int(
|
||||
time.time() + limit_time * 60 * 60
|
||||
if limit_time != 0 and new_time
|
||||
else 0
|
||||
),
|
||||
daily_limit
|
||||
)
|
||||
return True, name, tmp[:-1],
|
||||
|
||||
|
||||
def parse_goods_info(msg: str) -> Union[dict, str]:
|
||||
@@ -276,6 +336,10 @@ def parse_goods_info(msg: str) -> Union[dict, str]:
|
||||
data["discount"] = sp[1]
|
||||
elif sp[0] == "limit_time":
|
||||
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||
return "limit_time参数不合法,必须大于0!"
|
||||
return "limit_time参数不合法,必须为数字且大于0!"
|
||||
data["limit_time"] = sp[1]
|
||||
elif sp[0] == "daily_limit":
|
||||
if not is_number(sp[1]) or float(sp[1]) < 0:
|
||||
return "daily_limit参数不合法,必须为数字且大于0!"
|
||||
data["daily_limit"] = sp[1]
|
||||
return data
|
||||
|
||||
@@ -2,6 +2,10 @@ from typing import Optional
|
||||
from pathlib import Path
|
||||
from .utils import ConfigsManager
|
||||
|
||||
import platform
|
||||
if platform.system() == "Linux":
|
||||
import os
|
||||
hostip = os.popen("cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }'").read().replace("\n","")
|
||||
|
||||
# 回复消息名称
|
||||
NICKNAME: str = "小真寻"
|
||||
@@ -18,6 +22,7 @@ port: str = "" # 数据库端口
|
||||
database: str = "" # 数据库名称
|
||||
|
||||
# 代理,例如 "http://127.0.0.1:7890"
|
||||
# 如果是WLS 可以 f"http://{hostip}:7890" 使用寄主机的代理
|
||||
SYSTEM_PROXY: Optional[str] = None # 全局代理
|
||||
|
||||
|
||||
|
||||
+19
-19
@@ -22,9 +22,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_total_gold(cls, user_qq: int, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取金币概况
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
@@ -44,9 +44,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def get_gold(cls, user_qq: int, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取当前金币
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
@@ -64,9 +64,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def get_property(cls, user_qq: int, group_id: int) -> Dict[str, int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取当前道具
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
"""
|
||||
@@ -84,9 +84,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def add_gold(cls, user_qq: int, group_id: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
增加金币
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param num: 金币数量
|
||||
@@ -112,9 +112,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def spend_gold(cls, user_qq: int, group_id: int, num: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
花费金币
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param num: 金币数量
|
||||
@@ -140,9 +140,9 @@ class BagUser(db.Model):
|
||||
@classmethod
|
||||
async def add_property(cls, user_qq: int, group_id: int, name: str):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
增加道具
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param name: 道具名称
|
||||
@@ -165,9 +165,9 @@ class BagUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, name: str, num: int = 1
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
使用/删除 道具
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 所在群号
|
||||
:param name: 道具名称
|
||||
@@ -192,9 +192,9 @@ class BagUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, goods: "GoodsInfo", goods_num: int
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
购买道具
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param group_id: 所在群聊
|
||||
:param goods: 商品
|
||||
@@ -209,14 +209,14 @@ class BagUser(db.Model):
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"buy_property 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_all_users(cls, group_id: Optional[int] = None) -> List["BagUser"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有用户数据
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if not group_id:
|
||||
|
||||
+12
-12
@@ -15,9 +15,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def check_ban_level(cls, user_qq: int, level: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测ban掉目标的用户与unban用户的权限等级大小
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: unban用户的qq号
|
||||
:param level: ban掉目标用户的权限等级
|
||||
"""
|
||||
@@ -31,9 +31,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def check_ban_time(cls, user_qq: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测用户被ban时长
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
@@ -49,9 +49,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def is_ban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
判断用户是否被ban
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
if await cls.check_ban_time(user_qq):
|
||||
@@ -63,9 +63,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def is_super_ban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
判断用户是否被ban
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
user = await cls.query.where((cls.user_qq == user_qq)).gino.first()
|
||||
@@ -77,9 +77,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def ban(cls, user_qq: int, ban_level: int, duration: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
ban掉目标用户
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 目标用户qq号
|
||||
:param ban_level: 使用ban命令用户的权限
|
||||
:param duration: ban时长,秒
|
||||
@@ -104,9 +104,9 @@ class BanUser(db.Model):
|
||||
@classmethod
|
||||
async def unban(cls, user_qq: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
unban用户
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
"""
|
||||
query = cls.query.where((cls.user_qq == user_qq))
|
||||
|
||||
+18
-18
@@ -28,9 +28,9 @@ class ChatHistory(db.Model):
|
||||
days: Optional[int] = None,
|
||||
) -> List["ChatHistory"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户消息
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 用户qq
|
||||
:param msg_type: 消息类型,私聊或群聊
|
||||
:param days: 限制日期
|
||||
@@ -46,9 +46,9 @@ class ChatHistory(db.Model):
|
||||
date_scope: Tuple[datetime, datetime] = None,
|
||||
) -> List["ChatHistory"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群聊指定用户聊天记录
|
||||
参数:
|
||||
参数:
|
||||
:param uid: qq
|
||||
:param gid: 群号
|
||||
:param limit: 获取数量
|
||||
@@ -63,9 +63,9 @@ class ChatHistory(db.Model):
|
||||
@classmethod
|
||||
async def get_group_user_msg_count(cls, uid: int, gid: int) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查询群聊指定用户的聊天记录数量
|
||||
参数:
|
||||
参数:
|
||||
:param uid: qq
|
||||
:param gid: 群号
|
||||
"""
|
||||
@@ -86,9 +86,9 @@ class ChatHistory(db.Model):
|
||||
date_scope: Optional[Tuple[datetime, datetime]] = None,
|
||||
) -> Optional[Tuple[int, int]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取排行数据
|
||||
参数:
|
||||
参数:
|
||||
:param gid: 群号
|
||||
:param limit: 获取数量
|
||||
:param order: 排序类型,desc,des
|
||||
@@ -103,9 +103,9 @@ class ChatHistory(db.Model):
|
||||
@classmethod
|
||||
async def get_group_first_msg_datetime(cls, gid: int) -> Optional[datetime]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群第一条记录消息时间
|
||||
参数:
|
||||
参数:
|
||||
:param gid:
|
||||
"""
|
||||
if (
|
||||
@@ -124,9 +124,9 @@ class ChatHistory(db.Model):
|
||||
days: Optional[int] = None,
|
||||
) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户消息数量
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 用户qq
|
||||
:param msg_type: 消息类型,私聊或群聊
|
||||
:param days: 限制日期
|
||||
@@ -142,9 +142,9 @@ class ChatHistory(db.Model):
|
||||
days: Optional[int] = None,
|
||||
) -> List["ChatHistory"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群聊消息
|
||||
参数:
|
||||
参数:
|
||||
:param gid: 用户qq
|
||||
:param days: 限制日期
|
||||
"""
|
||||
@@ -157,9 +157,9 @@ class ChatHistory(db.Model):
|
||||
days: Optional[int] = None,
|
||||
) -> List["ChatHistory"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群聊消息数量
|
||||
参数:
|
||||
参数:
|
||||
:param gid: 用户qq
|
||||
:param days: 限制日期
|
||||
"""
|
||||
@@ -178,9 +178,9 @@ class ChatHistory(db.Model):
|
||||
is_select_count: bool = False,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取消息查询query
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 用户qq
|
||||
:param gid: 群号
|
||||
:param type_: 类型,私聊或群聊
|
||||
|
||||
+10
-10
@@ -15,9 +15,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_name(cls, user_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取好友用户名称
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
@@ -30,9 +30,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def add_friend_info(cls, user_id: int, user_name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加好友信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
:param user_name: 用户名称
|
||||
"""
|
||||
@@ -55,9 +55,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def delete_friend_info(cls, user_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除好友信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
try:
|
||||
@@ -72,9 +72,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def get_friend_nickname(cls, user_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户昵称
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
"""
|
||||
query = cls.query.where(cls.user_id == user_id)
|
||||
@@ -92,9 +92,9 @@ class FriendUser(db.Model):
|
||||
@classmethod
|
||||
async def set_friend_nickname(cls, user_id: int, nickname: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置用户昵称
|
||||
参数:
|
||||
参数:
|
||||
:param user_id: qq号
|
||||
:param nickname: 昵称
|
||||
"""
|
||||
|
||||
+102
-35
@@ -1,5 +1,5 @@
|
||||
from services.db_context import db
|
||||
from typing import Optional, List
|
||||
from typing import Optional, List, Tuple
|
||||
from services.log import logger
|
||||
|
||||
|
||||
@@ -12,27 +12,33 @@ class GoodsInfo(db.Model):
|
||||
goods_description = db.Column(db.TEXT(), nullable=False) # 商品描述
|
||||
goods_discount = db.Column(db.Numeric(scale=3, asdecimal=False), default=1) # 打折
|
||||
goods_limit_time = db.Column(db.BigInteger(), default=0) # 限时
|
||||
daily_limit = db.Column(db.Integer(), nullable=False, default=0) # 每日购买限制
|
||||
daily_purchase_limit = db.Column(
|
||||
db.JSON(), nullable=False, default={}
|
||||
) # 每日购买限制数据存储
|
||||
|
||||
_idx1 = db.Index("goods_group_users_idx1", "goods_name", unique=True)
|
||||
|
||||
@classmethod
|
||||
async def add_goods(
|
||||
cls,
|
||||
goods_name: str,
|
||||
goods_price: int,
|
||||
goods_description: str,
|
||||
goods_discount: float = 1,
|
||||
goods_limit_time: int = 0,
|
||||
cls,
|
||||
goods_name: str,
|
||||
goods_price: int,
|
||||
goods_description: str,
|
||||
goods_discount: float = 1,
|
||||
goods_limit_time: int = 0,
|
||||
daily_limit: int = 0,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加商品
|
||||
参数:
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param goods_price: 商品价格
|
||||
:param goods_description: 商品简介
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时
|
||||
:param daily_limit: 每日购买限制
|
||||
"""
|
||||
try:
|
||||
if not await cls.get_goods_info(goods_name):
|
||||
@@ -42,6 +48,7 @@ class GoodsInfo(db.Model):
|
||||
goods_description=goods_description,
|
||||
goods_discount=goods_discount,
|
||||
goods_limit_time=goods_limit_time,
|
||||
daily_limit=daily_limit,
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -51,15 +58,15 @@ class GoodsInfo(db.Model):
|
||||
@classmethod
|
||||
async def delete_goods(cls, goods_name: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除商品
|
||||
参数:
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
query = (
|
||||
await cls.query.where(cls.goods_name == goods_name)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not query:
|
||||
return False
|
||||
@@ -68,50 +75,51 @@ class GoodsInfo(db.Model):
|
||||
|
||||
@classmethod
|
||||
async def update_goods(
|
||||
cls,
|
||||
goods_name: str,
|
||||
goods_price: Optional[int] = None,
|
||||
goods_description: Optional[str] = None,
|
||||
goods_discount: Optional[float] = None,
|
||||
goods_limit_time: Optional[int] = None,
|
||||
cls,
|
||||
goods_name: str,
|
||||
goods_price: Optional[int] = None,
|
||||
goods_description: Optional[str] = None,
|
||||
goods_discount: Optional[float] = None,
|
||||
goods_limit_time: Optional[int] = None,
|
||||
daily_limit: Optional[int] = None
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
更新商品信息
|
||||
参数:
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
:param goods_price: 商品价格
|
||||
:param goods_description: 商品简介
|
||||
:param goods_discount: 商品折扣
|
||||
:param goods_limit_time: 商品限时时间
|
||||
:param daily_limit: 每日次数限制
|
||||
"""
|
||||
try:
|
||||
query = (
|
||||
await cls.query.where(cls.goods_name == goods_name)
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
.with_for_update()
|
||||
.gino.first()
|
||||
)
|
||||
if not query:
|
||||
return False
|
||||
if goods_price:
|
||||
await query.update(goods_price=goods_price).apply()
|
||||
if goods_description:
|
||||
await query.update(goods_description=goods_description).apply()
|
||||
if goods_discount:
|
||||
await query.update(goods_discount=goods_discount).apply()
|
||||
if goods_limit_time:
|
||||
await query.update(goods_limit_time=goods_limit_time).apply()
|
||||
await query.update(
|
||||
goods_price=goods_price or query.goods_price,
|
||||
goods_description=goods_description or query.goods_description,
|
||||
goods_discount=goods_discount or query.goods_discount,
|
||||
goods_limit_time=goods_limit_time if goods_limit_time is not None else query.goods_limit_time,
|
||||
daily_limit=daily_limit if daily_limit is not None else query.daily_limit,
|
||||
).apply()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"GoodsInfo update_goods 发生错误 {type(e)}:{e}")
|
||||
return False
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def get_goods_info(cls, goods_name: str) -> "GoodsInfo":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取商品对象
|
||||
参数:
|
||||
参数:
|
||||
:param goods_name: 商品名称
|
||||
"""
|
||||
return await cls.query.where(cls.goods_name == goods_name).gino.first()
|
||||
@@ -119,7 +127,7 @@ class GoodsInfo(db.Model):
|
||||
@classmethod
|
||||
async def get_all_goods(cls) -> List["GoodsInfo"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获得全部有序商品对象
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
@@ -130,3 +138,62 @@ class GoodsInfo(db.Model):
|
||||
goods_lst.append([x for x in query if x.id == min_id][0])
|
||||
id_lst.remove(min_id)
|
||||
return goods_lst
|
||||
|
||||
@classmethod
|
||||
async def add_user_daily_purchase(
|
||||
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
添加用户明日购买限制
|
||||
参数:
|
||||
:param goods: 商品
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param num: 数量
|
||||
"""
|
||||
user_id = str(user_id)
|
||||
group_id = str(group_id)
|
||||
if goods and goods.daily_limit and goods.daily_limit > 0:
|
||||
if not goods.daily_purchase_limit.get(group_id):
|
||||
goods.daily_purchase_limit[group_id] = {}
|
||||
if not goods.daily_purchase_limit[group_id].get(user_id):
|
||||
goods.daily_purchase_limit[group_id][user_id] = 0
|
||||
goods.daily_purchase_limit[group_id][user_id] += num
|
||||
await goods.update(daily_purchase_limit=goods.daily_purchase_limit).apply()
|
||||
|
||||
@classmethod
|
||||
async def check_user_daily_purchase(
|
||||
cls, goods: "GoodsInfo", user_id: int, group_id: int, num: int = 1
|
||||
) -> Tuple[bool, int]:
|
||||
"""
|
||||
说明:
|
||||
检测用户每日购买上限
|
||||
参数:
|
||||
:param goods: 商品
|
||||
:param user_id: 用户id
|
||||
:param group_id: 群号
|
||||
:param num: 数量
|
||||
"""
|
||||
user_id = str(user_id)
|
||||
group_id = str(group_id)
|
||||
if goods and goods.daily_limit > 0:
|
||||
if (
|
||||
not goods.daily_limit
|
||||
or not goods.daily_purchase_limit.get(group_id)
|
||||
or not goods.daily_purchase_limit[group_id].get(user_id)
|
||||
):
|
||||
return goods.daily_limit - num < 0, goods.daily_limit
|
||||
if goods.daily_purchase_limit[group_id][user_id] + num > goods.daily_limit:
|
||||
return (
|
||||
True,
|
||||
goods.daily_limit - goods.daily_purchase_limit[group_id][user_id],
|
||||
)
|
||||
return False, 0
|
||||
|
||||
@classmethod
|
||||
async def reset_daily_purchase(cls):
|
||||
"""
|
||||
重置每次次数限制
|
||||
"""
|
||||
await cls.update.values(daily_purchase_limit={}).gino.status()
|
||||
|
||||
@@ -17,9 +17,9 @@ class GroupInfo(db.Model):
|
||||
@classmethod
|
||||
async def get_group_info(cls, group_id: int) -> "GroupInfo":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群信息
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
query = cls.query.where(cls.group_id == group_id)
|
||||
@@ -35,9 +35,9 @@ class GroupInfo(db.Model):
|
||||
group_flag: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加群信息
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param group_name: 群名称
|
||||
:param max_member_count: 群员最大数量
|
||||
@@ -74,9 +74,9 @@ class GroupInfo(db.Model):
|
||||
@classmethod
|
||||
async def delete_group_info(cls, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除群信息
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
await cls.delete.where(cls.group_id == group_id).gino.status()
|
||||
@@ -84,7 +84,7 @@ class GroupInfo(db.Model):
|
||||
@classmethod
|
||||
async def get_all_group(cls) -> List["GroupInfo"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有群对象
|
||||
"""
|
||||
query = await cls.query.gino.all()
|
||||
|
||||
+14
-14
@@ -27,9 +27,9 @@ class GroupInfoUser(db.Model):
|
||||
uid: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加群内用户信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param user_name: 用户名称
|
||||
@@ -57,9 +57,9 @@ class GroupInfoUser(db.Model):
|
||||
cls, user_qq: int, group_id: int
|
||||
) -> "GroupInfoUser":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查询群员信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -71,9 +71,9 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def delete_member_info(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除群员信息
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -96,9 +96,9 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def get_group_member_id_list(cls, group_id: int) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取该群所有用户qq
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
member_list = []
|
||||
@@ -112,9 +112,9 @@ class GroupInfoUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, nickname: str
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置群员在该群内的昵称
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param nickname: 昵称
|
||||
@@ -131,9 +131,9 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_all_group(cls, user_qq: int) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取该用户所在的所有群聊
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = await cls.query.where(cls.user_qq == user_qq).gino.all()
|
||||
@@ -144,9 +144,9 @@ class GroupInfoUser(db.Model):
|
||||
@classmethod
|
||||
async def get_group_member_nickname(cls, user_qq: int, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户在该群的昵称
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
|
||||
+10
-10
@@ -17,9 +17,9 @@ class LevelUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_level(cls, user_qq: int, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户在群内的等级
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -35,9 +35,9 @@ class LevelUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, level: int, group_flag: int = 0
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置用户在群内的权限
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param level: 权限等级
|
||||
@@ -64,9 +64,9 @@ class LevelUser(db.Model):
|
||||
@classmethod
|
||||
async def delete_level(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除用户权限
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -82,9 +82,9 @@ class LevelUser(db.Model):
|
||||
@classmethod
|
||||
async def check_level(cls, user_qq: int, group_id: int, level: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检查用户权限等级是否大于 level
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param level: 权限等级
|
||||
@@ -112,9 +112,9 @@ class LevelUser(db.Model):
|
||||
@classmethod
|
||||
async def is_group_flag(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测是否会被自动更新刷新权限
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
|
||||
@@ -80,9 +80,9 @@ class SignGroupUser(db.Model):
|
||||
@classmethod
|
||||
async def get_all_impression(cls, group_id: int) -> "list, list, list":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取该群所有用户 id 及对应 好感度
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
impression_list = []
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
|
||||
|
||||
from utils.message_builder import at
|
||||
from .data_source import (
|
||||
add_live_sub,
|
||||
delete_sub,
|
||||
@@ -50,7 +52,17 @@ __plugin_configs__ = {
|
||||
"value": 5,
|
||||
"help": "群内bilibili订阅需要管理的权限",
|
||||
"default_value": 5,
|
||||
}
|
||||
},
|
||||
"LIVE_MSG_AT_ALL": {
|
||||
"value": False,
|
||||
"help": "直播提醒是否AT全体(仅在真寻是管理员时生效)",
|
||||
"default_value": False,
|
||||
},
|
||||
"UP_MSG_AT_ALL": {
|
||||
"value": False,
|
||||
"help": "UP动态投稿提醒是否AT全体(仅在真寻是管理员时生效)",
|
||||
"default_value": False,
|
||||
},
|
||||
}
|
||||
|
||||
add_sub = on_command("添加订阅", priority=5, block=True)
|
||||
@@ -233,10 +245,22 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
|
||||
for x in sub.sub_users.split(",")[:-1]:
|
||||
try:
|
||||
if ":" in x and x.split(":")[1] not in temp_group:
|
||||
temp_group.append(x.split(":")[1])
|
||||
await bot.send_group_msg(
|
||||
group_id=int(x.split(":")[1]), message=Message(rst)
|
||||
)
|
||||
group_id = int(x.split(":")[1])
|
||||
temp_group.append(group_id)
|
||||
if (
|
||||
await bot.get_group_member_info(
|
||||
group_id=group_id, user_id=int(bot.self_id), no_cache=True
|
||||
)
|
||||
)["role"] in ["owner", "admin"]:
|
||||
if (
|
||||
sub.sub_type == "live"
|
||||
and Config.get_config("bilibili_sub", "LIVE_MSG_AT_ALL")
|
||||
) or (
|
||||
sub.sub_type == "up"
|
||||
and Config.get_config("bilibili_sub", "UP_MSG_AT_ALL")
|
||||
):
|
||||
rst = "[CQ:at,qq=all]\n" + rst
|
||||
await bot.send_group_msg(group_id=group_id, message=Message(rst))
|
||||
else:
|
||||
await bot.send_private_msg(user_id=int(x), message=Message(rst))
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from bilireq.exceptions import ResponseCodeError
|
||||
from nonebot.adapters.onebot.v11 import MessageSegment
|
||||
|
||||
from utils.manager import resources_manager
|
||||
from asyncio.exceptions import TimeoutError
|
||||
|
||||
from utils.utils import get_bot
|
||||
from .model import BilibiliSub
|
||||
from bilireq.live import get_room_info_by_id
|
||||
from .utils import get_meta
|
||||
@@ -8,7 +12,7 @@ from utils.message_builder import image
|
||||
from bilireq.user import get_user_info
|
||||
from bilireq import dynamic
|
||||
from .utils import get_videos
|
||||
from typing import Optional
|
||||
from typing import Optional, Tuple
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from datetime import datetime
|
||||
from utils.browser import get_browser
|
||||
@@ -227,6 +231,7 @@ async def _get_live_status(id_: int) -> Optional[str]:
|
||||
await BilibiliSub.update_sub_info(id_, live_status=live_status)
|
||||
if sub.live_status == 0 and live_status == 1:
|
||||
return (
|
||||
f""
|
||||
f"{image(cover)}\n"
|
||||
f"{sub.uname} 开播啦!\n"
|
||||
f"标题:{title}\n"
|
||||
@@ -251,14 +256,14 @@ async def _get_up_status(id_: int) -> Optional[str]:
|
||||
video = None
|
||||
if _user.uname != uname:
|
||||
await BilibiliSub.update_sub_info(id_, uname=uname)
|
||||
dynamic_img, dynamic_upload_time = await get_user_dynamic(id_, _user)
|
||||
dynamic_img, dynamic_upload_time, link = await get_user_dynamic(id_, _user)
|
||||
if video_info["list"].get("vlist"):
|
||||
video = video_info["list"]["vlist"][0]
|
||||
latest_video_created = video["created"]
|
||||
rst = ""
|
||||
if dynamic_img:
|
||||
await BilibiliSub.update_sub_info(id_, dynamic_upload_time=dynamic_upload_time)
|
||||
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n"
|
||||
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n{link}"
|
||||
if (
|
||||
latest_video_created
|
||||
and _user.latest_video_created
|
||||
@@ -304,7 +309,7 @@ async def _get_season_status(id_) -> Optional[str]:
|
||||
|
||||
async def get_user_dynamic(
|
||||
uid: int, local_user: BilibiliSub
|
||||
) -> "Optional[MessageSegment], int":
|
||||
) -> Tuple[Optional[MessageSegment], int, str]:
|
||||
"""
|
||||
获取用户动态
|
||||
:param uid: 用户uid
|
||||
@@ -316,33 +321,50 @@ async def get_user_dynamic(
|
||||
browser = await get_browser()
|
||||
if dynamic_info.get("cards") and browser:
|
||||
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
|
||||
dynamic_id = dynamic_info["cards"][0]["desc"]["dynamic_id"]
|
||||
if local_user.dynamic_upload_time < dynamic_upload_time:
|
||||
page = await browser.new_page()
|
||||
context = await browser.new_context()
|
||||
page = await context.new_page()
|
||||
try:
|
||||
await page.goto(
|
||||
f"https://space.bilibili.com/{local_user.uid}/dynamic",
|
||||
f"https://t.bilibili.com/{dynamic_id}",
|
||||
wait_until="networkidle",
|
||||
timeout=10000,
|
||||
)
|
||||
await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
|
||||
# await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
|
||||
# 删除置顶
|
||||
# await page.evaluate(
|
||||
# """
|
||||
# xs = document.getElementsByClassName('bili-dyn-item__tag');
|
||||
# for (x of xs) {
|
||||
# x.parentNode.parentNode.remove();
|
||||
# }
|
||||
# """
|
||||
# )
|
||||
# async with page.expect_popup() as popup_info:
|
||||
# await page.locator(".bili-rich-text__content").click()
|
||||
# details_page = await popup_info.value
|
||||
await page.set_viewport_size(
|
||||
{"width": 2560, "height": 1080, "timeout": 10000 * 20}
|
||||
)
|
||||
await page.wait_for_selector(".panel-area")
|
||||
await page.evaluate(
|
||||
"""
|
||||
xs = document.getElementsByClassName('bili-dyn-item__tag');
|
||||
for (x of xs) {
|
||||
x.parentNode.parentNode.remove();
|
||||
}
|
||||
xs = document.getElementById('internationalHeader');
|
||||
xs.remove();
|
||||
xs = document.getElementsByClassName('panel-area')
|
||||
xs[0].remove();
|
||||
"""
|
||||
)
|
||||
card = page.locator(".bili-dyn-list__item").first
|
||||
card = page.locator(".detail-card")
|
||||
await card.wait_for()
|
||||
# 截图并保存
|
||||
await card.screenshot(
|
||||
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
|
||||
finally:
|
||||
await context.close()
|
||||
await page.close()
|
||||
return (
|
||||
image(
|
||||
@@ -350,8 +372,9 @@ async def get_user_dynamic(
|
||||
"bilibili_sub/dynamic",
|
||||
),
|
||||
dynamic_upload_time,
|
||||
f"https://t.bilibili.com/{dynamic_id}"
|
||||
)
|
||||
return None, None
|
||||
return None, 0, ''
|
||||
|
||||
|
||||
class SubManager:
|
||||
|
||||
@@ -47,9 +47,9 @@ class BilibiliSub(db.Model):
|
||||
season_update_time: Optional[datetime] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加订阅
|
||||
参数:
|
||||
参数:
|
||||
:param sub_id: 订阅名称,房间号,番剧号等
|
||||
:param sub_type: 订阅类型
|
||||
:param sub_user: 订阅此条目的用户
|
||||
@@ -110,9 +110,9 @@ class BilibiliSub(db.Model):
|
||||
@classmethod
|
||||
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除订阅
|
||||
参数:
|
||||
参数:
|
||||
:param sub_id: 订阅名称
|
||||
:param sub_user: 删除此条目的用户
|
||||
"""
|
||||
@@ -140,9 +140,9 @@ class BilibiliSub(db.Model):
|
||||
@classmethod
|
||||
async def get_sub(cls, sub_id: int) -> Optional["BilibiliSub"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取订阅对象
|
||||
参数:
|
||||
参数:
|
||||
:param sub_id: 订阅 id
|
||||
"""
|
||||
return await cls.query.where(cls.sub_id == sub_id).gino.first()
|
||||
@@ -173,9 +173,9 @@ class BilibiliSub(db.Model):
|
||||
season_update_time: Optional[datetime] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
更新订阅信息
|
||||
参数:
|
||||
参数:
|
||||
:param sub_id: 订阅名称,房间号,番剧号等
|
||||
:param live_short_id: 直接短 id
|
||||
:param live_status: 主播开播状态
|
||||
@@ -232,7 +232,7 @@ class BilibiliSub(db.Model):
|
||||
cls,
|
||||
) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
分类获取所有数据
|
||||
"""
|
||||
live_data = []
|
||||
|
||||
+10
-10
@@ -25,9 +25,9 @@ class BlackWord(db.Model):
|
||||
punish_level: int,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加用户发送的敏感词
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户id
|
||||
:param group_id: 群号
|
||||
:param black_word: 黑名单词汇
|
||||
@@ -52,9 +52,9 @@ class BlackWord(db.Model):
|
||||
id_: Optional[int] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置处罚
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户id
|
||||
:param punish: 处罚
|
||||
:param black_word: 黑名单词汇
|
||||
@@ -81,9 +81,9 @@ class BlackWord(db.Model):
|
||||
cls, user_qq: int, days: int = 7, punish_level: Optional[int] = None
|
||||
) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户规定周期内的犯事次数
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param days: 周期天数
|
||||
:param punish_level: 惩罚等级
|
||||
@@ -101,9 +101,9 @@ class BlackWord(db.Model):
|
||||
@classmethod
|
||||
async def get_user_punish_level(cls, user_qq: int, days: int = 7) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户最近一次的惩罚记录等级
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param days: 周期天数
|
||||
"""
|
||||
@@ -125,9 +125,9 @@ class BlackWord(db.Model):
|
||||
date_type: str = "=",
|
||||
) -> List["BlackWord"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过指定条件查询数据
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param group_id: 群号
|
||||
:param date: 日期
|
||||
|
||||
@@ -9,7 +9,7 @@ import platform
|
||||
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
|
||||
|
||||
url = "http://www.eclzz.one/"
|
||||
url = "http://www.eclzz.zone/"
|
||||
|
||||
|
||||
async def get_bt_info(keyword: str, page: int):
|
||||
|
||||
@@ -71,7 +71,6 @@ async def _(bot: Bot):
|
||||
)
|
||||
|
||||
|
||||
|
||||
@restart.got("flag", prompt=f"确定是否重启{NICKNAME}?确定请回复[是|好|确定](重启失败咱们将失去联系,请谨慎!)")
|
||||
async def _(flag: str = ArgStr("flag")):
|
||||
if flag.lower() in ["true", "是", "好", "确定", "确定是"]:
|
||||
|
||||
+20
-13
@@ -1,4 +1,7 @@
|
||||
from typing import Tuple, Any
|
||||
|
||||
from nonebot import on_regex
|
||||
from nonebot.params import RegexGroup
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
|
||||
from utils.message_builder import image
|
||||
@@ -11,7 +14,9 @@ __plugin_usage__ = """
|
||||
usage:
|
||||
三次元也不戳,嘿嘿嘿
|
||||
指令:
|
||||
cos/coser
|
||||
?N连cos/coser
|
||||
示例:cos
|
||||
示例:5连cos (单次请求张数小于9)
|
||||
""".strip()
|
||||
__plugin_des__ = "三次元也不戳,嘿嘿嘿"
|
||||
__plugin_cmd__ = ["cos/coser"]
|
||||
@@ -31,21 +36,23 @@ __plugin_configs__ = {
|
||||
},
|
||||
}
|
||||
|
||||
coser = on_regex("^(cos|COS|coser|括丝)$", priority=5, block=True)
|
||||
coser = on_regex(r"^(\d)连?(cos|COS|coser|括丝)$", priority=5, block=True)
|
||||
|
||||
|
||||
url = "https://api.iyk0.com/cos"
|
||||
|
||||
|
||||
@coser.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
try:
|
||||
msg_id = await coser.send(image(url))
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id["message_id"],
|
||||
Config.get_config("coser", "WITHDRAW_COS_MESSAGE"),
|
||||
)
|
||||
except Exception as e:
|
||||
await coser.send("你cos给我看!")
|
||||
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
|
||||
async def _(bot: Bot, event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||
num = reg_group[0] or 1
|
||||
for _ in range(int(num)):
|
||||
try:
|
||||
msg_id = await coser.send(image(url))
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id["message_id"],
|
||||
Config.get_config("coser", "WITHDRAW_COS_MESSAGE"),
|
||||
)
|
||||
except Exception as e:
|
||||
await coser.send("你cos给我看!")
|
||||
logger.error(f"coser 发送了未知错误 {type(e)}:{e}")
|
||||
|
||||
@@ -30,7 +30,7 @@ class Map:
|
||||
ratio: float = 1,
|
||||
):
|
||||
"""
|
||||
参数:
|
||||
参数:
|
||||
:param resource_name: 资源名称
|
||||
:param center_point: 中心点
|
||||
:param deviation: 坐标误差
|
||||
|
||||
@@ -25,9 +25,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def add_uid(cls, user_qq: int, uid: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加一个uid
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
@@ -44,9 +44,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_mys_id(cls, uid: int, mys_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置米游社id
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param mys_id: 米游社id
|
||||
"""
|
||||
@@ -60,9 +60,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_bind_group(cls, uid: int, bind_group) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
绑定group_id,除私聊外的提醒将在此群发送
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
:param bind_group: 群号
|
||||
"""
|
||||
@@ -76,9 +76,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_bind_group(cls, uid: int) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户绑定的群聊
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
"""
|
||||
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -89,9 +89,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_cookie(cls, uid: int, cookie: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param cookie: 米游社id
|
||||
"""
|
||||
@@ -105,9 +105,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_resin_remind(cls, uid: int, flag: bool) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置体力提醒
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param flag: 开关状态
|
||||
"""
|
||||
@@ -121,9 +121,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_user_resin_recovery_time(cls, uid: int, date: datetime):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置体力完成时间
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
:param date: 提醒日期
|
||||
"""
|
||||
@@ -134,9 +134,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_resin_recovery_time(cls, uid: int) -> Optional[datetime]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取体力完成时间
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
"""
|
||||
u = await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -147,7 +147,7 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_all_resin_remind_user(cls) -> List["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有开启体力提醒的用户
|
||||
"""
|
||||
return await cls.query.where(cls.resin_remind == True).gino.all()
|
||||
@@ -155,9 +155,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def clear_resin_remind_time(cls, uid: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
清空提醒日期
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
"""
|
||||
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -169,9 +169,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置米游社/原神自动签到
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param flag: 开关状态
|
||||
"""
|
||||
@@ -185,7 +185,7 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_all_auto_sign_user(cls) -> List["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有开启自动签到的用户
|
||||
"""
|
||||
return await cls.query.where(cls.auto_sign == True).gino.all()
|
||||
@@ -193,7 +193,7 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_all_sign_user(cls) -> List["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取 原神 所有今日签到用户
|
||||
"""
|
||||
return await cls.query.where(cls.auto_sign_time != None).gino.all()
|
||||
@@ -201,9 +201,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def clear_sign_time(cls, uid: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
清空签到日期
|
||||
参数:
|
||||
参数:
|
||||
:param uid: uid
|
||||
"""
|
||||
user = await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -215,9 +215,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def random_sign_time(cls, uid: int) -> Optional[datetime]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
随机签到时间
|
||||
说明:
|
||||
说明:
|
||||
:param uid: uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
@@ -245,9 +245,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_query_cookie(cls, uid: int) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取查询角色信息cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
# 查找用户今日是否已经查找过,防止重复
|
||||
@@ -265,9 +265,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid:原神uid
|
||||
:param flag:必须使用自己的cookie
|
||||
"""
|
||||
@@ -279,9 +279,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_by_qq(cls, user_qq: int) -> Optional["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过qq获取用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq
|
||||
"""
|
||||
return await cls.query.where(cls.user_qq == user_qq).gino.first()
|
||||
@@ -289,9 +289,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_by_uid(cls, uid: int) -> Optional["Genshin"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过uid获取用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param uid: qq
|
||||
"""
|
||||
return await cls.query.where(cls.uid == uid).gino.first()
|
||||
@@ -299,9 +299,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def get_user_uid(cls, user_qq: int) -> Optional[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户uid
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq:用户qq
|
||||
"""
|
||||
return await cls._get_user_data(user_qq, None, "uid")
|
||||
@@ -311,7 +311,7 @@ class Genshin(db.Model):
|
||||
"""
|
||||
说嘛:
|
||||
获取用户米游社id
|
||||
参数:
|
||||
参数:
|
||||
:param uid:原神id
|
||||
"""
|
||||
return await cls._get_user_data(None, uid, "mys_id")
|
||||
@@ -319,9 +319,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def delete_user_cookie(cls, uid: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除用户cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
"""
|
||||
query = cls.query.where(cls.uid == uid).with_for_update()
|
||||
@@ -332,9 +332,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def delete_user(cls, user_qq: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除用户数据
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
"""
|
||||
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
|
||||
@@ -347,9 +347,9 @@ class Genshin(db.Model):
|
||||
@classmethod
|
||||
async def _add_query_uid(cls, uid: int, cookie_uid: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加每日查询重复uid的cookie
|
||||
参数:
|
||||
参数:
|
||||
:param uid: 原神uid
|
||||
:param cookie_uid: cookie的uid
|
||||
"""
|
||||
@@ -362,9 +362,9 @@ class Genshin(db.Model):
|
||||
cls, user_qq: Optional[int], uid: Optional[int], type_: str
|
||||
) -> Optional[Union[int, str]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户数据
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: 用户qq
|
||||
:param uid: uid
|
||||
:param type_: 数据类型
|
||||
|
||||
@@ -18,9 +18,9 @@ class RedbagUser(db.Model):
|
||||
@classmethod
|
||||
async def add_redbag_data(cls, user_qq: int, group_id: int, itype: str, money: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加收发红包数据
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 收或发
|
||||
@@ -45,9 +45,9 @@ class RedbagUser(db.Model):
|
||||
@classmethod
|
||||
async def ensure(cls, user_qq: int, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -61,9 +61,9 @@ class RedbagUser(db.Model):
|
||||
@classmethod
|
||||
async def get_user_all(cls, group_id: int = None) -> List["RedbagUser"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if not group_id:
|
||||
|
||||
@@ -65,8 +65,8 @@ async def arg_handle(
|
||||
if int(img_id) > max_id or int(img_id) < 0:
|
||||
await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
|
||||
try:
|
||||
if (TEMP_PATH / "delete.jpg").exists():
|
||||
(TEMP_PATH / "delete.jpg").unlink()
|
||||
if (TEMP_PATH / f"{event.user_id}_delete.jpg").exists():
|
||||
(TEMP_PATH / f"{event.user_id}_delete.jpg").unlink()
|
||||
logger.info(f"删除{cn2py(state['path'])}图片 {img_id}.jpg 成功")
|
||||
except Exception as e:
|
||||
logger.warning(f"删除图片 delete.jpg 失败 e{e}")
|
||||
|
||||
@@ -31,7 +31,7 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
|
||||
async with db.transaction():
|
||||
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
|
||||
# 一天次数上限
|
||||
if user.today_open_total == int(
|
||||
if user.today_open_total > int(
|
||||
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
|
||||
+ int(impression)
|
||||
/ Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
|
||||
|
||||
+163
-165
@@ -1,165 +1,163 @@
|
||||
# from nonebot import on_message
|
||||
# from services.log import logger
|
||||
# from nonebot.adapters.onebot.v11 import GroupMessageEvent, ActionFailed
|
||||
# from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
|
||||
# from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
# from utils.message_builder import image
|
||||
# from utils.image_utils import BuildImage
|
||||
# from utils.browser import get_browser
|
||||
# from configs.path_config import IMAGE_PATH
|
||||
# from utils.http_utils import AsyncHttpx
|
||||
# from configs.config import Config
|
||||
# from utils.user_agent import get_user_agent
|
||||
# import aiohttp
|
||||
# import asyncio
|
||||
# import time
|
||||
# import ujson as json
|
||||
#
|
||||
#
|
||||
# __zx_plugin_name__ = "B站转发解析"
|
||||
# __plugin_usage__ = """
|
||||
# usage:
|
||||
# B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
|
||||
# """.strip()
|
||||
# __plugin_des__ = "B站转发解析"
|
||||
# __plugin_type__ = ("其他",)
|
||||
# __plugin_version__ = 0.1
|
||||
# __plugin_author__ = "HibiKier"
|
||||
# __plugin_task__ = {"bilibili_parse": "b站转发解析"}
|
||||
# Config.add_plugin_config(
|
||||
# "_task",
|
||||
# "DEFAULT_BILIBILI_PARSE",
|
||||
# True,
|
||||
# help_="被动 B站转发解析 进群默认开关状态",
|
||||
# default_value=True,
|
||||
# )
|
||||
#
|
||||
#
|
||||
# parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
|
||||
#
|
||||
# _tmp = {}
|
||||
#
|
||||
#
|
||||
# @parse_bilibili_json.handle()
|
||||
# async def _(event: GroupMessageEvent):
|
||||
# vd_info = None
|
||||
# url = None
|
||||
# if get_message_json(event.json()):
|
||||
# try:
|
||||
# data = json.loads(get_message_json(event.json())[0]["data"])
|
||||
# except (IndexError, KeyError):
|
||||
# data = None
|
||||
# if data:
|
||||
# # 转发视频
|
||||
# if data.get("desc") == "哔哩哔哩":
|
||||
# async with aiohttp.ClientSession(
|
||||
# headers=get_user_agent()
|
||||
# ) as session:
|
||||
# async with session.get(
|
||||
# data["meta"]["detail_1"]["qqdocurl"],
|
||||
# proxy=get_local_proxy(),
|
||||
# timeout=7,
|
||||
# ) as response:
|
||||
# url = str(response.url).split("?")[0]
|
||||
# bvid = url.split("/")[-1]
|
||||
# vd_info = await video.Video(bvid=bvid).get_info()
|
||||
# # response = await AsyncHttpx.get(
|
||||
# # data["meta"]["detail_1"]["qqdocurl"], timeout=7
|
||||
# # )
|
||||
# # url = str(response.url).split("?")[0]
|
||||
# # bvid = url.split("/")[-1]
|
||||
# # vd_info = await video.Video(bvid=bvid).get_info()
|
||||
# # 转发专栏
|
||||
# if (
|
||||
# data.get("meta")
|
||||
# and data["meta"].get("news")
|
||||
# and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
|
||||
# ):
|
||||
# url = data["meta"]["news"]["jumpUrl"]
|
||||
# page = None
|
||||
# try:
|
||||
# browser = await get_browser()
|
||||
# if not browser:
|
||||
# return
|
||||
# page = await browser.new_page(
|
||||
# user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||||
# " (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
|
||||
# )
|
||||
# await page.goto(url, wait_until="networkidle", timeout=10000)
|
||||
# await page.set_viewport_size({"width": 2560, "height": 1080})
|
||||
# await page.click("#app > div")
|
||||
# div = await page.query_selector("#app > div")
|
||||
# await div.screenshot(
|
||||
# path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
|
||||
# timeout=100000,
|
||||
# )
|
||||
# await asyncio.get_event_loop().run_in_executor(
|
||||
# None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
|
||||
# )
|
||||
# await parse_bilibili_json.send(
|
||||
# "[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
|
||||
# )
|
||||
# await page.close()
|
||||
# logger.info(
|
||||
# f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
|
||||
# )
|
||||
# except Exception as e:
|
||||
# logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
|
||||
# if page:
|
||||
# await page.close()
|
||||
# return
|
||||
# # BV
|
||||
# if msg := get_message_text(event.json()):
|
||||
# if "BV" in msg:
|
||||
# index = msg.find("BV")
|
||||
# if len(msg[index + 2 :]) >= 10:
|
||||
# msg = msg[index : index + 12]
|
||||
# url = f"https://www.bilibili.com/video/{msg}"
|
||||
# vd_info = await video.Video(bvid=msg).get_info()
|
||||
# elif "av" in msg:
|
||||
# index = msg.find("av")
|
||||
# if len(msg[index + 2 :]) >= 9:
|
||||
# msg = msg[index + 2 : index + 11]
|
||||
# if is_number(msg):
|
||||
# url = f"https://www.bilibili.com/video/{msg}"
|
||||
# vd_info = await video.Video(aid=int(msg)).get_info()
|
||||
# elif "https://b23.tv" in msg:
|
||||
# url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13]
|
||||
# res = await AsyncHttpx.get(url, timeout=7)
|
||||
# url = str(res.url).split("?")[0]
|
||||
# bvid = url.split("/")[-1]
|
||||
# vd_info = await video.Video(bvid=bvid).get_info()
|
||||
# if vd_info:
|
||||
# if (
|
||||
# url in _tmp.keys() and time.time() - _tmp[url] > 30
|
||||
# ) or url not in _tmp.keys():
|
||||
# _tmp[url] = time.time()
|
||||
# aid = vd_info["aid"]
|
||||
# title = vd_info["title"]
|
||||
# author = vd_info["owner"]["name"]
|
||||
# reply = vd_info["stat"]["reply"] # 回复
|
||||
# favorite = vd_info["stat"]["favorite"] # 收藏
|
||||
# coin = vd_info["stat"]["coin"] # 投币
|
||||
# # like = vd_info['stat']['like'] # 点赞
|
||||
# # danmu = vd_info['stat']['danmaku'] # 弹幕
|
||||
# date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
|
||||
# try:
|
||||
# await parse_bilibili_json.send(
|
||||
# "[[_task|bilibili_parse]]" +
|
||||
# image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
|
||||
# f"UP:{author}\n"
|
||||
# f"上传日期:{date}\n"
|
||||
# f"回复:{reply},收藏:{favorite},投币:{coin}\n"
|
||||
# f"{url}"
|
||||
# )
|
||||
# except ActionFailed:
|
||||
# logger.warning(f"{event.group_id} 发送bilibili解析失败")
|
||||
# else:
|
||||
# logger.info(
|
||||
# f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
|
||||
# )
|
||||
#
|
||||
#
|
||||
# def resize(path: str):
|
||||
# A = BuildImage(0, 0, background=path, ratio=0.5)
|
||||
# A.save(path)
|
||||
from nonebot import on_message
|
||||
from services.log import logger
|
||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, ActionFailed
|
||||
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
|
||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||
from utils.message_builder import image
|
||||
from utils.image_utils import BuildImage
|
||||
from utils.browser import get_browser
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from configs.config import Config
|
||||
from utils.user_agent import get_user_agent
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import time
|
||||
import ujson as json
|
||||
from bilireq import video
|
||||
__zx_plugin_name__ = "B站转发解析"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
|
||||
""".strip()
|
||||
__plugin_des__ = "B站转发解析"
|
||||
__plugin_type__ = ("其他",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_task__ = {"bilibili_parse": "b站转发解析"}
|
||||
Config.add_plugin_config(
|
||||
"_task",
|
||||
"DEFAULT_BILIBILI_PARSE",
|
||||
True,
|
||||
help_="被动 B站转发解析 进群默认开关状态",
|
||||
default_value=True,
|
||||
)
|
||||
|
||||
|
||||
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
|
||||
|
||||
_tmp = {}
|
||||
|
||||
|
||||
@parse_bilibili_json.handle()
|
||||
async def _(event: GroupMessageEvent):
|
||||
vd_info = None
|
||||
url = None
|
||||
if get_message_json(event.json()):
|
||||
try:
|
||||
data = json.loads(get_message_json(event.json())[0]["data"])
|
||||
except (IndexError, KeyError):
|
||||
data = None
|
||||
if data:
|
||||
# 转发视频
|
||||
if data.get("desc") == "哔哩哔哩":
|
||||
async with aiohttp.ClientSession(
|
||||
headers=get_user_agent()
|
||||
) as session:
|
||||
async with session.get(
|
||||
data["meta"]["detail_1"]["qqdocurl"],
|
||||
timeout=7,
|
||||
) as response:
|
||||
url = str(response.url).split("?")[0]
|
||||
bvid = url.split("/")[-1]
|
||||
vd_info = await video.get_video_base_info(bvid)
|
||||
# 转发专栏
|
||||
if (
|
||||
data.get("meta")
|
||||
and data["meta"].get("news")
|
||||
and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
|
||||
):
|
||||
url = data["meta"]["news"]["jumpUrl"]
|
||||
page = None
|
||||
try:
|
||||
browser = await get_browser()
|
||||
if not browser:
|
||||
return
|
||||
page = await browser.new_page(
|
||||
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
|
||||
" (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
|
||||
)
|
||||
await page.goto(url, wait_until="networkidle", timeout=10000)
|
||||
await page.set_viewport_size({"width": 2560, "height": 1080})
|
||||
await page.click("#app > div")
|
||||
div = await page.query_selector("#app > div")
|
||||
await div.screenshot(
|
||||
path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
|
||||
timeout=100000,
|
||||
)
|
||||
await asyncio.get_event_loop().run_in_executor(
|
||||
None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
|
||||
)
|
||||
await parse_bilibili_json.send(
|
||||
"[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
|
||||
)
|
||||
await page.close()
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
|
||||
if page:
|
||||
await page.close()
|
||||
return
|
||||
# BV
|
||||
if msg := get_message_text(event.json()):
|
||||
if "BV" in msg:
|
||||
index = msg.find("BV")
|
||||
if len(msg[index + 2 :]) >= 10:
|
||||
msg = msg[index : index + 12]
|
||||
url = f"https://www.bilibili.com/video/{msg}"
|
||||
vd_info = await video.get_video_base_info(msg)
|
||||
elif "av" in msg:
|
||||
index = msg.find("av")
|
||||
if len(msg[index + 2 :]) >= 9:
|
||||
msg = msg[index + 2 : index + 11]
|
||||
if is_number(msg):
|
||||
url = f"https://www.bilibili.com/video/{msg}"
|
||||
vd_info = await video.get_video_base_info(msg)
|
||||
elif "https://b23.tv" in msg:
|
||||
url = "https://" + msg[msg.find("b23.tv"): msg.find("b23.tv") + 14]
|
||||
async with aiohttp.ClientSession(
|
||||
headers=get_user_agent()
|
||||
) as session:
|
||||
async with session.get(
|
||||
url,
|
||||
timeout=7,
|
||||
) as response:
|
||||
url = str(response.url).split("?")[0]
|
||||
bvid = url.split("/")[-1]
|
||||
vd_info = await video.get_video_base_info(bvid)
|
||||
if vd_info:
|
||||
if (
|
||||
url in _tmp.keys() and time.time() - _tmp[url] > 30
|
||||
) or url not in _tmp.keys():
|
||||
_tmp[url] = time.time()
|
||||
aid = vd_info["aid"]
|
||||
title = vd_info["title"]
|
||||
author = vd_info["owner"]["name"]
|
||||
reply = vd_info["stat"]["reply"] # 回复
|
||||
favorite = vd_info["stat"]["favorite"] # 收藏
|
||||
coin = vd_info["stat"]["coin"] # 投币
|
||||
# like = vd_info['stat']['like'] # 点赞
|
||||
# danmu = vd_info['stat']['danmaku'] # 弹幕
|
||||
date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
|
||||
try:
|
||||
await parse_bilibili_json.send(
|
||||
"[[_task|bilibili_parse]]" +
|
||||
image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
|
||||
f"UP:{author}\n"
|
||||
f"上传日期:{date}\n"
|
||||
f"回复:{reply},收藏:{favorite},投币:{coin}\n"
|
||||
f"{url}"
|
||||
)
|
||||
except ActionFailed:
|
||||
logger.warning(f"{event.group_id} 发送bilibili解析失败")
|
||||
else:
|
||||
logger.info(
|
||||
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
|
||||
)
|
||||
|
||||
|
||||
def resize(path: str):
|
||||
A = BuildImage(0, 0, background=path, ratio=0.5)
|
||||
A.save(path)
|
||||
|
||||
@@ -38,9 +38,9 @@ class OmegaPixivIllusts(db.Model):
|
||||
updated_at: datetime,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加图片信息
|
||||
参数:
|
||||
参数:
|
||||
:param pid: pid
|
||||
:param title: 标题
|
||||
:param width: 宽度
|
||||
@@ -78,9 +78,9 @@ class OmegaPixivIllusts(db.Model):
|
||||
num: int = 100
|
||||
) -> List[Optional["OmegaPixivIllusts"]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查找符合条件的图片
|
||||
参数:
|
||||
参数:
|
||||
:param keywords: 关键词
|
||||
:param uid: 画师uid
|
||||
:param pid: 图片pid
|
||||
@@ -104,9 +104,9 @@ class OmegaPixivIllusts(db.Model):
|
||||
@classmethod
|
||||
async def check_exists(cls, pid: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测pid是否已存在
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片PID
|
||||
"""
|
||||
query = await cls.query.where(cls.pid == pid).gino.all()
|
||||
@@ -115,9 +115,9 @@ class OmegaPixivIllusts(db.Model):
|
||||
@classmethod
|
||||
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int, int":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取相关关键词(keyword, tag)在图库中的数量
|
||||
参数:
|
||||
参数:
|
||||
:param tags: 关键词/Tag
|
||||
"""
|
||||
setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count'))
|
||||
@@ -133,7 +133,7 @@ class OmegaPixivIllusts(db.Model):
|
||||
@classmethod
|
||||
async def get_all_pid(cls) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有图片PID
|
||||
"""
|
||||
data = await cls.select('pid').gino.all()
|
||||
|
||||
@@ -38,9 +38,9 @@ class Pixiv(db.Model):
|
||||
tags: str,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加图片信息
|
||||
参数:
|
||||
参数:
|
||||
:param pid: pid
|
||||
:param title: 标题
|
||||
:param width: 宽度
|
||||
@@ -74,9 +74,9 @@ class Pixiv(db.Model):
|
||||
@classmethod
|
||||
async def remove_image_data(cls, pid: int, img_p: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除图片数据
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
:param img_p: 图片pid的张数,如:p0,p1
|
||||
"""
|
||||
@@ -94,7 +94,7 @@ class Pixiv(db.Model):
|
||||
@classmethod
|
||||
async def get_all_pid(cls) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有PID
|
||||
"""
|
||||
query = await cls.query.select("pid").gino.first()
|
||||
@@ -112,9 +112,9 @@ class Pixiv(db.Model):
|
||||
num: int = 100
|
||||
) -> List[Optional["Pixiv"]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查找符合条件的图片
|
||||
参数:
|
||||
参数:
|
||||
:param keywords: 关键词
|
||||
:param uid: 画师uid
|
||||
:param pid: 图片pid
|
||||
@@ -140,9 +140,9 @@ class Pixiv(db.Model):
|
||||
@classmethod
|
||||
async def check_exists(cls, pid: int, img_p: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测pid是否已存在
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片PID
|
||||
:param img_p: 张数
|
||||
"""
|
||||
@@ -154,9 +154,9 @@ class Pixiv(db.Model):
|
||||
@classmethod
|
||||
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取相关关键词(keyword, tag)在图库中的数量
|
||||
参数:
|
||||
参数:
|
||||
:param tags: 关键词/Tag
|
||||
"""
|
||||
setattr(Pixiv, 'count', db.func.count(cls.pid).label('count'))
|
||||
|
||||
@@ -19,9 +19,9 @@ class PixivKeywordUser(db.Model):
|
||||
cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str]
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加搜图的关键词
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param keyword: 关键词
|
||||
@@ -38,9 +38,9 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def delete_keyword(cls, keyword: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除关键词
|
||||
参数:
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
"""
|
||||
if await cls._check_keyword_exists(keyword):
|
||||
@@ -53,9 +53,9 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过或禁用关键词
|
||||
参数:
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
:param is_pass: 通过状态
|
||||
"""
|
||||
@@ -71,7 +71,7 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def get_all_user_dict(cls) -> dict:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取关键词数据库各个用户贡献的关键词字典
|
||||
"""
|
||||
tmp = {}
|
||||
@@ -85,7 +85,7 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def get_current_keyword(cls) -> "List[str], List[str]":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取当前通过与未通过的关键词
|
||||
"""
|
||||
pass_keyword = []
|
||||
@@ -101,7 +101,7 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def get_black_pid(cls) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取黑名单PID
|
||||
"""
|
||||
black_pid = []
|
||||
@@ -113,9 +113,9 @@ class PixivKeywordUser(db.Model):
|
||||
@classmethod
|
||||
async def _check_keyword_exists(cls, keyword: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测关键词是否已存在
|
||||
参数:
|
||||
参数:
|
||||
:param keyword: 关键词
|
||||
"""
|
||||
current_keyword = []
|
||||
|
||||
@@ -132,6 +132,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
|
||||
all_image = await OmegaPixivIllusts.query_images(
|
||||
pid=int(pid), nsfw_tag=nsfw_tag
|
||||
)
|
||||
num = len(all_image)
|
||||
else:
|
||||
tmp = await Pixiv.query_images(
|
||||
x, r18=1 if nsfw_tag == 2 else 0, num=pix_num
|
||||
|
||||
@@ -184,7 +184,7 @@ async def _():
|
||||
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
|
||||
omega_pixiv_illusts = None
|
||||
for file in os.listdir("."):
|
||||
if "omega_pixiv_illusts" in file and ".sql" in file:
|
||||
if "omega_pixiv_artwork" in file and ".sql" in file:
|
||||
omega_pixiv_illusts = Path() / file
|
||||
if omega_pixiv_illusts:
|
||||
with open(omega_pixiv_illusts, "r", encoding="utf8") as f:
|
||||
|
||||
@@ -17,7 +17,7 @@ __zx_plugin_name__ = "P站排行/搜图"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
P站排行:
|
||||
可选参数:
|
||||
可选参数:
|
||||
类型:
|
||||
1. 日排行
|
||||
2. 周排行
|
||||
|
||||
@@ -23,9 +23,9 @@ class RussianUser(db.Model):
|
||||
@classmethod
|
||||
async def ensure(cls, user_qq: int, group_id: int) -> "RussianUser":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
"""
|
||||
@@ -39,9 +39,9 @@ class RussianUser(db.Model):
|
||||
@classmethod
|
||||
async def add_count(cls, user_qq: int, group_id: int, itype: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加用户输赢次数
|
||||
说明:
|
||||
说明:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 输或赢 'win' or 'lose'
|
||||
@@ -87,9 +87,9 @@ class RussianUser(db.Model):
|
||||
@classmethod
|
||||
async def money(cls, user_qq: int, group_id: int, itype: str, count: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加用户输赢金钱
|
||||
参数:
|
||||
参数:
|
||||
:param user_qq: qq号
|
||||
:param group_id: 群号
|
||||
:param itype: 输或赢 'win' or 'lose'
|
||||
@@ -120,9 +120,9 @@ class RussianUser(db.Model):
|
||||
@classmethod
|
||||
async def get_all_user(cls, group_id: int) -> List["RussianUser"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取该群所有用户对象
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
users = await cls.query.where((cls.group_id == group_id)).gino.all()
|
||||
|
||||
@@ -30,9 +30,9 @@ class Setu(db.Model):
|
||||
tags: str,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加一份色图数据
|
||||
参数:
|
||||
参数:
|
||||
:param local_id: 本地存储id
|
||||
:param title: 标题
|
||||
:param author: 作者
|
||||
@@ -62,9 +62,9 @@ class Setu(db.Model):
|
||||
limit: int = 50,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过tag查找色图
|
||||
参数:
|
||||
参数:
|
||||
:param local_id: 本地色图 id
|
||||
:param tags: tags
|
||||
:param r18: 是否 r18,0:非r18 1:r18 2:混合
|
||||
@@ -90,7 +90,7 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def get_image_count(cls, r18: int = 0) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查询图片数量
|
||||
"""
|
||||
flag = False if r18 == 0 else True
|
||||
@@ -101,9 +101,9 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def get_image_in_hash(cls, img_hash: str) -> "Setu":
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
通过图像hash获取图像信息
|
||||
参数:
|
||||
参数:
|
||||
:param img_hash: = 图像hash值
|
||||
"""
|
||||
query = await cls.query.where(cls.img_hash == img_hash).gino.first()
|
||||
@@ -112,9 +112,9 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def _check_exists(cls, pid: int, img_url: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测图片是否存在
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
:param img_url: 图片链接
|
||||
"""
|
||||
@@ -127,9 +127,9 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def delete_image(cls, pid: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除图片并替换
|
||||
参数:
|
||||
参数:
|
||||
:param pid: 图片pid
|
||||
"""
|
||||
query = await cls.query.where(cls.pid == pid).gino.first()
|
||||
@@ -157,9 +157,9 @@ class Setu(db.Model):
|
||||
tags: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
根据PID修改图片数据
|
||||
参数:
|
||||
参数:
|
||||
:param local_id: 本地id
|
||||
:param pid: 图片pid
|
||||
:param title: 标题
|
||||
@@ -190,7 +190,7 @@ class Setu(db.Model):
|
||||
@classmethod
|
||||
async def get_all_setu(cls) -> List["Setu"]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有图片对象
|
||||
"""
|
||||
return await cls.query.gino.all()
|
||||
|
||||
@@ -6,9 +6,10 @@ from nonebot.message import run_postprocessor
|
||||
from nonebot.matcher import Matcher
|
||||
from typing import Optional, Type, Any
|
||||
from gino.exceptions import UninitializedError
|
||||
|
||||
from utils.message_builder import custom_forward_msg
|
||||
from utils.utils import (
|
||||
is_number,
|
||||
get_message_img,
|
||||
)
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
@@ -98,6 +99,11 @@ __plugin_configs__ = {
|
||||
"TIMEOUT": {"value": 10, "help": "色图下载超时限制(秒)", "default_value": 10},
|
||||
"SHOW_INFO": {"value": True, "help": "是否显示色图的基本信息,如PID等", "default_value": True},
|
||||
"ALLOW_GROUP_R18": {"value": False, "help": "在群聊中启用R18权限", "default_value": False},
|
||||
"MAX_ONCE_NUM2FORWARD": {
|
||||
"value": None,
|
||||
"help": "单次发送的图片数量达到指定值时转发为合并消息",
|
||||
"default_value": None,
|
||||
},
|
||||
}
|
||||
Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pixiv.re", help_="Pixiv反向代理")
|
||||
|
||||
@@ -133,7 +139,10 @@ setu_reg = on_regex("(.*)[份|发|张|个|次|点](.*)[瑟|色|涩]图$", priori
|
||||
|
||||
@setu.handle()
|
||||
async def _(
|
||||
event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()
|
||||
bot: Bot,
|
||||
event: MessageEvent,
|
||||
cmd: Tuple[str, ...] = Command(),
|
||||
arg: Message = CommandArg(),
|
||||
):
|
||||
msg = arg.extract_plain_text().strip()
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
@@ -149,10 +158,7 @@ async def _(
|
||||
if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent):
|
||||
r18 = 1
|
||||
num = 10
|
||||
elif (
|
||||
cmd[0] == "色图r"
|
||||
and isinstance(event, GroupMessageEvent)
|
||||
):
|
||||
elif cmd[0] == "色图r" and isinstance(event, GroupMessageEvent):
|
||||
if not Config.get_config("send_setu", "ALLOW_GROUP_R18"):
|
||||
await setu.finish(
|
||||
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
|
||||
@@ -178,7 +184,7 @@ async def _(
|
||||
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
|
||||
)
|
||||
return
|
||||
await send_setu_handle(setu, event, cmd[0], msg, num, r18)
|
||||
await send_setu_handle(bot, setu, event, cmd[0], msg, num, r18)
|
||||
|
||||
|
||||
num_key = {
|
||||
@@ -197,7 +203,7 @@ num_key = {
|
||||
|
||||
|
||||
@setu_reg.handle()
|
||||
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||
async def _(bot: Bot, event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||
if isinstance(event, GroupMessageEvent):
|
||||
impression = (
|
||||
await SignGroupUser.ensure(event.user_id, event.group_id)
|
||||
@@ -214,10 +220,11 @@ async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||
num = int(num)
|
||||
except ValueError:
|
||||
num = 1
|
||||
await send_setu_handle(setu_reg, event, "色图", tags, num, 0)
|
||||
await send_setu_handle(bot, setu_reg, event, "色图", tags, num, 0)
|
||||
|
||||
|
||||
async def send_setu_handle(
|
||||
bot: Bot,
|
||||
matcher: Type[Matcher],
|
||||
event: MessageEvent,
|
||||
command: str,
|
||||
@@ -247,8 +254,10 @@ async def send_setu_handle(
|
||||
if code == 401:
|
||||
await setu.finish(urls[0], at_sender=True)
|
||||
if code == 200:
|
||||
forward_list = []
|
||||
for i in range(len(urls)):
|
||||
try:
|
||||
msg_id = None
|
||||
setu_img, index = await search_online_setu(urls[i])
|
||||
# 下载成功的话
|
||||
if index != -1:
|
||||
@@ -257,9 +266,17 @@ async def send_setu_handle(
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 发送色图 {index}.png"
|
||||
)
|
||||
msg_id = await matcher.send(
|
||||
Message(f"{text_list[i]}\n{setu_img}")
|
||||
)
|
||||
if (
|
||||
Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
|
||||
and num
|
||||
>= Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
|
||||
and isinstance(event, GroupMessageEvent)
|
||||
):
|
||||
forward_list.append(Message(f"{text_list[i]}\n{setu_img}"))
|
||||
else:
|
||||
msg_id = await matcher.send(
|
||||
Message(f"{text_list[i]}\n{setu_img}")
|
||||
)
|
||||
else:
|
||||
if setu_list is None:
|
||||
setu_list, code = await get_setu_list(tags=tags, r18=r18)
|
||||
@@ -268,14 +285,35 @@ async def send_setu_handle(
|
||||
if setu_list:
|
||||
setu_image = random.choice(setu_list)
|
||||
setu_list.remove(setu_image)
|
||||
msg_id = await matcher.send(
|
||||
Message(
|
||||
gen_message(setu_image)
|
||||
+ (
|
||||
await check_local_exists_or_download(setu_image)
|
||||
)[0]
|
||||
if (
|
||||
Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
|
||||
and num
|
||||
>= Config.get_config(
|
||||
"send_setu", "MAX_ONCE_NUM2FORWARD"
|
||||
)
|
||||
and isinstance(event, GroupMessageEvent)
|
||||
):
|
||||
forward_list.append(
|
||||
Message(
|
||||
gen_message(setu_image)
|
||||
+ (
|
||||
await check_local_exists_or_download(
|
||||
setu_image
|
||||
)
|
||||
)[0]
|
||||
)
|
||||
)
|
||||
else:
|
||||
msg_id = await matcher.send(
|
||||
Message(
|
||||
gen_message(setu_image)
|
||||
+ (
|
||||
await check_local_exists_or_download(
|
||||
setu_image
|
||||
)
|
||||
)[0]
|
||||
)
|
||||
)
|
||||
)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
@@ -291,6 +329,16 @@ async def send_setu_handle(
|
||||
)
|
||||
except ActionFailed:
|
||||
await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
|
||||
if forward_list:
|
||||
msg_id = await bot.send_group_forward_msg(
|
||||
group_id=event.group_id,
|
||||
messages=custom_forward_msg(forward_list, bot.self_id),
|
||||
)
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id,
|
||||
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
|
||||
)
|
||||
return
|
||||
if code != 200:
|
||||
await matcher.finish("网络连接失败...", at_sender=True)
|
||||
@@ -300,27 +348,48 @@ async def send_setu_handle(
|
||||
if code != 200:
|
||||
await matcher.finish(setu_list[0], at_sender=True)
|
||||
# 开始发图
|
||||
forward_list = []
|
||||
for _ in range(num):
|
||||
if not setu_list:
|
||||
await setu.finish("坏了,已经没图了,被榨干了!")
|
||||
setu_image = random.choice(setu_list)
|
||||
setu_list.remove(setu_image)
|
||||
try:
|
||||
msg_id = await matcher.send(
|
||||
if (
|
||||
Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
|
||||
and num >= Config.get_config("send_setu", "MAX_ONCE_NUM2FORWARD")
|
||||
and isinstance(event, GroupMessageEvent)
|
||||
):
|
||||
forward_list.append(
|
||||
Message(
|
||||
gen_message(setu_image)
|
||||
+ (await check_local_exists_or_download(setu_image))[0]
|
||||
)
|
||||
)
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id["message_id"],
|
||||
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
|
||||
)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 发送本地色图 {setu_image.local_id}.png"
|
||||
)
|
||||
except ActionFailed:
|
||||
await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
|
||||
else:
|
||||
try:
|
||||
msg_id = await matcher.send(
|
||||
Message(
|
||||
gen_message(setu_image)
|
||||
+ (await check_local_exists_or_download(setu_image))[0]
|
||||
)
|
||||
)
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event,
|
||||
msg_id["message_id"],
|
||||
Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
|
||||
)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, GROUP "
|
||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||
f" 发送本地色图 {setu_image.local_id}.png"
|
||||
)
|
||||
except ActionFailed:
|
||||
await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
|
||||
if forward_list:
|
||||
msg_id = await bot.send_group_forward_msg(
|
||||
group_id=event.group_id,
|
||||
messages=custom_forward_msg(forward_list, bot.self_id),
|
||||
)
|
||||
withdraw_message_manager.withdraw_message(
|
||||
event, msg_id, Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE")
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ async def get_setu_urls(
|
||||
params = {
|
||||
"r18": r18, # 添加r18参数 0为否,1为是,2为混合
|
||||
"tag": tags, # 若指定tag
|
||||
"num": 100, # 一次返回的结果数量
|
||||
"num": 20, # 一次返回的结果数量
|
||||
"size": ["original"],
|
||||
}
|
||||
for count in range(3):
|
||||
|
||||
@@ -21,10 +21,16 @@ gConfig.add_plugin_config("web-ui", "password", None, name="web-ui", help_="前
|
||||
# 先使用hook修复
|
||||
@run_preprocessor
|
||||
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
|
||||
flag = False
|
||||
for module in plugins2settings_manager.keys():
|
||||
if isinstance(plugins2settings_manager.get_plugin_data(module).get("cmd"), str):
|
||||
plugins2settings_manager.set_module_data(
|
||||
module,
|
||||
"cmd",
|
||||
plugins2settings_manager.get_plugin_data(module).get("cmd").split(","),
|
||||
False
|
||||
)
|
||||
flag = True
|
||||
if flag:
|
||||
plugins2settings_manager.save()
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ async def _(user: User = Depends(token_to_user)) -> Result:
|
||||
|
||||
async def get_system_data(user: User = Depends(token_to_user)):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取系统信息,资源文件大小,网络状态等
|
||||
"""
|
||||
baidu = 200
|
||||
@@ -107,7 +107,7 @@ async def get_system_data(user: User = Depends(token_to_user)):
|
||||
|
||||
def _get_system_status(user: User = Depends(token_to_user)) -> SystemStatus:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取系统信息等
|
||||
"""
|
||||
cpu = psutil.cpu_percent()
|
||||
@@ -126,7 +126,7 @@ def _get_system_disk(
|
||||
type_: Optional[str], user: User = Depends(token_to_user)
|
||||
) -> Union[SystemFolderSize, Dict[str, Union[float, datetime]]]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取资源文件大小等
|
||||
"""
|
||||
if not type_:
|
||||
@@ -171,9 +171,9 @@ def _get_system_disk(
|
||||
|
||||
def _get_dir_size(dir_path: Path) -> float:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取文件夹大小
|
||||
参数:
|
||||
参数:
|
||||
:param dir_path: 文件夹路径
|
||||
"""
|
||||
size = 0
|
||||
@@ -184,9 +184,9 @@ def _get_dir_size(dir_path: Path) -> float:
|
||||
|
||||
def save_system_data(cpu: float, memory: float, disk: float):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
保存一些系统信息
|
||||
参数:
|
||||
参数:
|
||||
:param cpu: cpu
|
||||
:param memory: memory
|
||||
:param disk: disk
|
||||
|
||||
Generated
+276
-646
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -19,7 +19,7 @@ aiohttp = "3.7.4.post0"
|
||||
beautifulsoup4 = "4.9.3"
|
||||
feedparser = "^6.0.8"
|
||||
gino = "^1.0.1"
|
||||
httpx = "^0.22.0"
|
||||
httpx = "^0.23.0"
|
||||
ImageHash = "^4.2.1"
|
||||
jieba = "^0.42.1"
|
||||
lxml = "4.6.5"
|
||||
@@ -39,7 +39,7 @@ dateparser = "^1.1.0"
|
||||
cn2an = "^0.5.16"
|
||||
python-jose = "^3.3.0"
|
||||
python-multipart = "^0.0.5"
|
||||
bilireq = "^0.1.2"
|
||||
bilireq = "^0.2.0"
|
||||
emoji = "^1.7.0"
|
||||
wordcloud = "^1.8.1"
|
||||
rich = "^12.4.3"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
+2
-1
@@ -10,7 +10,8 @@
|
||||
"poetry.lock",
|
||||
"pyproject.toml",
|
||||
"resources/font",
|
||||
"bot.py"
|
||||
"resources/image/zhenxun",
|
||||
"resources/image/other"
|
||||
],
|
||||
"add_file": [],
|
||||
"delete_file": []
|
||||
|
||||
+2
-7
@@ -2,14 +2,9 @@ import asyncio
|
||||
from typing import Optional
|
||||
from nonebot.log import logger
|
||||
from playwright.async_api import Browser, async_playwright
|
||||
import nonebot
|
||||
from nonebot import Driver
|
||||
from services.log import logger
|
||||
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
_browser: Optional[Browser] = None
|
||||
|
||||
|
||||
@@ -20,8 +15,8 @@ async def init(**kwargs) -> Optional[Browser]:
|
||||
_browser = await browser.chromium.launch(**kwargs)
|
||||
return _browser
|
||||
except Exception as e:
|
||||
logger.warning(f"启动chromium发生错误 {type(e)}:{e}")
|
||||
asyncio.get_event_loop().run_in_executor(None, install)
|
||||
# logger.warning(f"启动chromium发生错误 {type(e)}:{e}")
|
||||
await asyncio.get_event_loop().run_in_executor(None, install)
|
||||
_browser = await browser.chromium.launch(**kwargs)
|
||||
return None
|
||||
|
||||
|
||||
+2
-2
@@ -10,9 +10,9 @@ async def init_rank(
|
||||
title: str, all_user_id: List[int], all_user_data: List[int], group_id: int, total_count: int = 10
|
||||
) -> BuildMat:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
初始化通用的数据排行榜
|
||||
参数:
|
||||
参数:
|
||||
:param title: 排行榜标题
|
||||
:param all_user_id: 所有用户的qq号
|
||||
:param all_user_data: 所有用户需要排行的对应数据
|
||||
|
||||
+30
-4
@@ -20,12 +20,15 @@ class ShopRegister(dict):
|
||||
discount: Tuple[float, ...],
|
||||
limit_time: Tuple[int, ...],
|
||||
load_status: Tuple[bool, ...],
|
||||
daily_limit: Tuple[int, ...],
|
||||
**kwargs,
|
||||
):
|
||||
def add_register_item(func: Callable):
|
||||
if name in self._data.keys():
|
||||
raise ValueError("该商品已注册,请替换其他名称!")
|
||||
for n, p, d, dd, l, s in zip(name, price, des, discount, limit_time, load_status):
|
||||
for n, p, d, dd, l, s, dl in zip(
|
||||
name, price, des, discount, limit_time, load_status, daily_limit
|
||||
):
|
||||
if s:
|
||||
_temp_kwargs = {}
|
||||
for key, value in kwargs.items():
|
||||
@@ -38,6 +41,7 @@ class ShopRegister(dict):
|
||||
"des": d,
|
||||
"discount": dd,
|
||||
"limit_time": l,
|
||||
"daily_limit": dl,
|
||||
"func": func,
|
||||
"kwargs": _temp_kwargs,
|
||||
}
|
||||
@@ -52,7 +56,12 @@ class ShopRegister(dict):
|
||||
self._flag = False
|
||||
for name in self._data.keys():
|
||||
await shop.register_goods(
|
||||
name, self._data[name]["price"], self._data[name]["des"], self._data[name]["discount"], self._data[name]["limit_time"]
|
||||
name,
|
||||
self._data[name]["price"],
|
||||
self._data[name]["des"],
|
||||
self._data[name]["discount"],
|
||||
self._data[name]["limit_time"],
|
||||
self._data[name]["daily_limit"],
|
||||
)
|
||||
use.register_use(
|
||||
name, self._data[name]["func"], **self._data[name]["kwargs"]
|
||||
@@ -66,6 +75,7 @@ class ShopRegister(dict):
|
||||
discount: Union[float, Tuple[float, ...]] = 1,
|
||||
limit_time: Union[int, Tuple[int, ...]] = 0,
|
||||
load_status: Union[bool, Tuple[bool, ...]] = True,
|
||||
daily_limit: Union[int, Tuple[int, ...]] = 0,
|
||||
**kwargs,
|
||||
):
|
||||
_tuple_list = []
|
||||
@@ -75,7 +85,9 @@ class ShopRegister(dict):
|
||||
if _current_len == -1:
|
||||
_current_len = len(x)
|
||||
if _current_len != len(x):
|
||||
raise ValueError(f"注册商品 {name} 中 name,price,des,discount,limit_time,load_status 数量不符!")
|
||||
raise ValueError(
|
||||
f"注册商品 {name} 中 name,price,des,discount,limit_time,load_status,daily_limit 数量不符!"
|
||||
)
|
||||
_current_len = _current_len if _current_len > -1 else 1
|
||||
_name = name if isinstance(name, tuple) else (name,)
|
||||
_price = (
|
||||
@@ -101,7 +113,21 @@ class ShopRegister(dict):
|
||||
if isinstance(load_status, tuple)
|
||||
else tuple([load_status for _ in range(_current_len)])
|
||||
)
|
||||
return self.register(_name, _price, _des, _discount, _limit_time, _load_status, **kwargs)
|
||||
_daily_limit = (
|
||||
daily_limit
|
||||
if isinstance(daily_limit, tuple)
|
||||
else tuple([daily_limit for _ in range(_current_len)])
|
||||
)
|
||||
return self.register(
|
||||
_name,
|
||||
_price,
|
||||
_des,
|
||||
_discount,
|
||||
_limit_time,
|
||||
_load_status,
|
||||
_daily_limit,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._data[key] = value
|
||||
|
||||
+29
-15
@@ -6,7 +6,7 @@ from pathlib import Path
|
||||
from httpx import Response
|
||||
from asyncio.exceptions import TimeoutError
|
||||
from nonebot.adapters.onebot.v11 import MessageSegment
|
||||
from playwright.async_api import Page
|
||||
from playwright.async_api import Page, BrowserContext
|
||||
from .message_builder import image
|
||||
from httpx import ConnectTimeout
|
||||
from .browser import get_browser
|
||||
@@ -37,9 +37,9 @@ class AsyncHttpx:
|
||||
**kwargs,
|
||||
) -> Response:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
Get
|
||||
参数:
|
||||
参数:
|
||||
:param url: url
|
||||
:param params: params
|
||||
:param headers: 请求头
|
||||
@@ -80,9 +80,9 @@ class AsyncHttpx:
|
||||
**kwargs,
|
||||
) -> Response:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
Post
|
||||
参数:
|
||||
参数:
|
||||
:param url: url
|
||||
:param data: data
|
||||
:param content: content
|
||||
@@ -129,12 +129,13 @@ class AsyncHttpx:
|
||||
**kwargs,
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
下载文件
|
||||
参数:
|
||||
参数:
|
||||
:param url: url
|
||||
:param path: 存储路径
|
||||
:param params: params
|
||||
:param verify: verify
|
||||
:param use_proxy: 使用代理
|
||||
:param proxy: 指定代理
|
||||
:param headers: 请求头
|
||||
@@ -223,9 +224,9 @@ class AsyncHttpx:
|
||||
**kwargs,
|
||||
) -> List[bool]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
分组同时下载文件
|
||||
参数:
|
||||
参数:
|
||||
:param url_list: url列表
|
||||
:param path_list: 存储路径列表
|
||||
:param limit_async_number: 限制同时请求数量
|
||||
@@ -287,9 +288,9 @@ class AsyncPlaywright:
|
||||
@classmethod
|
||||
async def _new_page(cls, user_agent: Optional[str] = None, **kwargs) -> Page:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取一个新页面
|
||||
参数:
|
||||
参数:
|
||||
:param user_agent: 请求头
|
||||
"""
|
||||
browser = await get_browser()
|
||||
@@ -297,6 +298,19 @@ class AsyncPlaywright:
|
||||
return await browser.new_page(user_agent=user_agent, **kwargs)
|
||||
raise BrowserIsNone("获取Browser失败...")
|
||||
|
||||
@classmethod
|
||||
async def new_context(cls, user_agent: Optional[str] = None, **kwargs) -> BrowserContext:
|
||||
"""
|
||||
说明:
|
||||
获取一个新上下文
|
||||
参数:
|
||||
:param user_agent: 请求头
|
||||
"""
|
||||
browser = await get_browser()
|
||||
if browser:
|
||||
return await browser.new_context(user_agent=user_agent, **kwargs)
|
||||
raise BrowserIsNone("获取Browser失败...")
|
||||
|
||||
@classmethod
|
||||
async def goto(
|
||||
cls,
|
||||
@@ -310,9 +324,9 @@ class AsyncPlaywright:
|
||||
**kwargs
|
||||
) -> Optional[Page]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
goto
|
||||
参数:
|
||||
参数:
|
||||
:param url: 网址
|
||||
:param timeout: 超时限制
|
||||
:param wait_until: 等待类型
|
||||
@@ -346,9 +360,9 @@ class AsyncPlaywright:
|
||||
**kwargs
|
||||
) -> Optional[MessageSegment]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
截图,该方法仅用于简单快捷截图,复杂截图请操作 page
|
||||
参数:
|
||||
参数:
|
||||
:param url: 网址
|
||||
:param path: 存储路径
|
||||
:param element: 元素选择
|
||||
|
||||
+109
-109
@@ -24,9 +24,9 @@ def compare_image_with_hash(
|
||||
image_file1: str, image_file2: str, max_dif: int = 1.5
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
比较两张图片的hash值是否相同
|
||||
参数:
|
||||
参数:
|
||||
:param image_file1: 图片文件路径
|
||||
:param image_file2: 图片文件路径
|
||||
:param max_dif: 允许最大hash差值, 越小越精确,最小为0
|
||||
@@ -45,9 +45,9 @@ def compare_image_with_hash(
|
||||
|
||||
def get_img_hash(image_file: Union[str, Path]) -> ImageHash:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取图片的hash值
|
||||
参数:
|
||||
参数:
|
||||
:param image_file: 图片文件路径
|
||||
"""
|
||||
with open(image_file, "rb") as fp:
|
||||
@@ -59,9 +59,9 @@ def compressed_image(
|
||||
in_file: Union[str, Path], out_file: Union[str, Path] = None, ratio: float = 0.9
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
压缩图片
|
||||
参数:
|
||||
参数:
|
||||
:param in_file: 被压缩的文件路径
|
||||
:param out_file: 压缩后输出的文件路径
|
||||
:param ratio: 压缩率,宽高 * 压缩率
|
||||
@@ -80,9 +80,9 @@ def compressed_image(
|
||||
|
||||
def alpha2white_pil(pic: Image) -> Image:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
将图片透明背景转化为白色
|
||||
参数:
|
||||
参数:
|
||||
:param pic: 通过PIL打开的图片文件
|
||||
"""
|
||||
img = pic.convert("RGBA")
|
||||
@@ -99,9 +99,9 @@ def alpha2white_pil(pic: Image) -> Image:
|
||||
|
||||
def pic2b64(pic: Image) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
PIL图片转base64
|
||||
参数:
|
||||
参数:
|
||||
:param pic: 通过PIL打开的图片文件
|
||||
"""
|
||||
buf = BytesIO()
|
||||
@@ -112,9 +112,9 @@ def pic2b64(pic: Image) -> str:
|
||||
|
||||
def fig2b64(plt_: plt) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
matplotlib图片转base64
|
||||
参数:
|
||||
参数:
|
||||
:param plt_: matplotlib生成的图片
|
||||
"""
|
||||
buf = BytesIO()
|
||||
@@ -125,9 +125,9 @@ def fig2b64(plt_: plt) -> str:
|
||||
|
||||
def is_valid(file: Union[str, Path]) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
判断图片是否损坏
|
||||
参数:
|
||||
参数:
|
||||
:param file: 图片文件路径
|
||||
"""
|
||||
valid = True
|
||||
@@ -160,7 +160,7 @@ class BuildImage:
|
||||
font_color: Optional[Union[str, Tuple[int, int, int]]] = None,
|
||||
):
|
||||
"""
|
||||
参数:
|
||||
参数:
|
||||
:param w: 自定义图片的宽度,w=0时为图片原本宽度
|
||||
:param h: 自定义图片的高度,h=0时为图片原本高度
|
||||
:param paste_image_width: 当图片做为背景图时,设置贴图的宽度,用于贴图自动换行
|
||||
@@ -241,9 +241,9 @@ class BuildImage:
|
||||
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 贴图
|
||||
参数:
|
||||
参数:
|
||||
:param img: 已打开的图片文件,可以为 BuildImage 或 Image
|
||||
:param pos: 贴图位置(左上角)
|
||||
:param alpha: 图片背景是否为透明
|
||||
@@ -259,9 +259,9 @@ class BuildImage:
|
||||
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
贴图
|
||||
参数:
|
||||
参数:
|
||||
:param img: 已打开的图片文件,可以为 BuildImage 或 Image
|
||||
:param pos: 贴图位置(左上角)
|
||||
:param alpha: 图片背景是否为透明
|
||||
@@ -304,9 +304,9 @@ class BuildImage:
|
||||
|
||||
def getsize(self, msg: str) -> Tuple[int, int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取文字在该图片 font_size 下所需要的空间
|
||||
参数:
|
||||
参数:
|
||||
:param msg: 文字内容
|
||||
"""
|
||||
return self.font.getsize(msg)
|
||||
@@ -315,9 +315,9 @@ class BuildImage:
|
||||
self, pos: Tuple[int, int], fill: Optional[Tuple[int, int, int]] = None
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 绘制多个或单独的像素
|
||||
参数:
|
||||
参数:
|
||||
:param pos: 坐标
|
||||
:param fill: 填错颜色
|
||||
"""
|
||||
@@ -325,9 +325,9 @@ class BuildImage:
|
||||
|
||||
def point(self, pos: Tuple[int, int], fill: Optional[Tuple[int, int, int]] = None):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
绘制多个或单独的像素
|
||||
参数:
|
||||
参数:
|
||||
:param pos: 坐标
|
||||
:param fill: 填错颜色
|
||||
"""
|
||||
@@ -341,9 +341,9 @@ class BuildImage:
|
||||
width: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 绘制圆
|
||||
参数:
|
||||
参数:
|
||||
:param pos: 坐标范围
|
||||
:param fill: 填充颜色
|
||||
:param outline: 描线颜色
|
||||
@@ -359,9 +359,9 @@ class BuildImage:
|
||||
width: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
绘制圆
|
||||
参数:
|
||||
参数:
|
||||
:param pos: 坐标范围
|
||||
:param fill: 填充颜色
|
||||
:param outline: 描线颜色
|
||||
@@ -377,9 +377,9 @@ class BuildImage:
|
||||
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 在图片上添加文字
|
||||
参数:
|
||||
参数:
|
||||
:param pos: 文字位置
|
||||
:param text: 文字内容
|
||||
:param fill: 文字颜色
|
||||
@@ -395,9 +395,9 @@ class BuildImage:
|
||||
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
在图片上添加文字
|
||||
参数:
|
||||
参数:
|
||||
:param pos: 文字位置
|
||||
:param text: 文字内容
|
||||
:param fill: 文字颜色
|
||||
@@ -424,18 +424,18 @@ class BuildImage:
|
||||
|
||||
async def asave(self, path: Optional[Union[str, Path]] = None):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 保存图片
|
||||
参数:
|
||||
参数:
|
||||
:param path: 图片路径
|
||||
"""
|
||||
await self.loop.run_in_executor(None, self.save, path)
|
||||
|
||||
def save(self, path: Optional[Union[str, Path]] = None):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
保存图片
|
||||
参数:
|
||||
参数:
|
||||
:param path: 图片路径
|
||||
"""
|
||||
if not path:
|
||||
@@ -444,16 +444,16 @@ class BuildImage:
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
显示图片
|
||||
"""
|
||||
self.markImg.show(self.markImg)
|
||||
|
||||
async def aresize(self, ratio: float = 0, w: int = 0, h: int = 0):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 压缩图片
|
||||
参数:
|
||||
参数:
|
||||
:param ratio: 压缩倍率
|
||||
:param w: 压缩图片宽度至 w
|
||||
:param h: 压缩图片高度至 h
|
||||
@@ -462,9 +462,9 @@ class BuildImage:
|
||||
|
||||
def resize(self, ratio: float = 0, w: int = 0, h: int = 0):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
压缩图片
|
||||
参数:
|
||||
参数:
|
||||
:param ratio: 压缩倍率
|
||||
:param w: 压缩图片宽度至 w
|
||||
:param h: 压缩图片高度至 h
|
||||
@@ -481,18 +481,18 @@ class BuildImage:
|
||||
|
||||
async def acrop(self, box: Tuple[int, int, int, int]):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 裁剪图片
|
||||
参数:
|
||||
参数:
|
||||
:param box: 左上角坐标,右下角坐标 (left, upper, right, lower)
|
||||
"""
|
||||
await self.loop.run_in_executor(None, self.crop, box)
|
||||
|
||||
def crop(self, box: Tuple[int, int, int, int]):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
裁剪图片
|
||||
参数:
|
||||
参数:
|
||||
:param box: 左上角坐标,右下角坐标 (left, upper, right, lower)
|
||||
"""
|
||||
self.markImg = self.markImg.crop(box)
|
||||
@@ -502,18 +502,18 @@ class BuildImage:
|
||||
|
||||
def check_font_size(self, word: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检查文本所需宽度是否大于图片宽度
|
||||
参数:
|
||||
参数:
|
||||
:param word: 文本内容
|
||||
"""
|
||||
return self.font.getsize(word)[0] > self.w
|
||||
|
||||
async def atransparent(self, alpha_ratio: float = 1, n: int = 0):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 图片透明化
|
||||
参数:
|
||||
参数:
|
||||
:param alpha_ratio: 透明化程度
|
||||
:param n: 透明化大小内边距
|
||||
"""
|
||||
@@ -521,9 +521,9 @@ class BuildImage:
|
||||
|
||||
def transparent(self, alpha_ratio: float = 1, n: int = 0):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
图片透明化
|
||||
参数:
|
||||
参数:
|
||||
:param alpha_ratio: 透明化程度
|
||||
:param n: 透明化大小内边距
|
||||
"""
|
||||
@@ -538,7 +538,7 @@ class BuildImage:
|
||||
|
||||
def pic2bs4(self) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
BuildImage 转 base64
|
||||
"""
|
||||
buf = BytesIO()
|
||||
@@ -548,9 +548,9 @@ class BuildImage:
|
||||
|
||||
def convert(self, type_: str):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
修改图片类型
|
||||
参数:
|
||||
参数:
|
||||
:param type_: 类型
|
||||
"""
|
||||
self.markImg = self.markImg.convert(type_)
|
||||
@@ -563,9 +563,9 @@ class BuildImage:
|
||||
width: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 画框
|
||||
参数:
|
||||
参数:
|
||||
:param xy: 坐标
|
||||
:param fill: 填充颜色
|
||||
:param outline: 轮廓颜色
|
||||
@@ -581,9 +581,9 @@ class BuildImage:
|
||||
width: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
画框
|
||||
参数:
|
||||
参数:
|
||||
:param xy: 坐标
|
||||
:param fill: 填充颜色
|
||||
:param outline: 轮廓颜色
|
||||
@@ -600,7 +600,7 @@ class BuildImage:
|
||||
"""
|
||||
说明:
|
||||
异步 画多边形
|
||||
参数:
|
||||
参数:
|
||||
:param xy: 坐标
|
||||
:param fill: 颜色
|
||||
:param outline: 线宽
|
||||
@@ -616,7 +616,7 @@ class BuildImage:
|
||||
"""
|
||||
说明:
|
||||
画多边形
|
||||
参数:
|
||||
参数:
|
||||
:param xy: 坐标
|
||||
:param fill: 颜色
|
||||
:param outline: 线宽
|
||||
@@ -630,9 +630,9 @@ class BuildImage:
|
||||
width: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 画线
|
||||
参数:
|
||||
参数:
|
||||
:param xy: 坐标
|
||||
:param fill: 填充
|
||||
:param width: 线宽
|
||||
@@ -646,9 +646,9 @@ class BuildImage:
|
||||
width: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
画线
|
||||
参数:
|
||||
参数:
|
||||
:param xy: 坐标
|
||||
:param fill: 填充
|
||||
:param width: 线宽
|
||||
@@ -657,14 +657,14 @@ class BuildImage:
|
||||
|
||||
async def acircle(self):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 将 BuildImage 图片变为圆形
|
||||
"""
|
||||
await self.loop.run_in_executor(None, self.circle)
|
||||
|
||||
def circle(self):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
使图像变圆
|
||||
"""
|
||||
self.markImg.convert("RGBA")
|
||||
@@ -693,18 +693,18 @@ class BuildImage:
|
||||
|
||||
async def acircle_corner(self, radii: int = 30):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 矩形四角变圆
|
||||
参数:
|
||||
参数:
|
||||
:param radii: 半径
|
||||
"""
|
||||
await self.loop.run_in_executor(None, self.circle_corner, radii)
|
||||
|
||||
def circle_corner(self, radii: int = 30):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
矩形四角变圆
|
||||
参数:
|
||||
参数:
|
||||
:param radii: 半径
|
||||
"""
|
||||
# 画圆(用于分离4个角)
|
||||
@@ -724,9 +724,9 @@ class BuildImage:
|
||||
|
||||
async def arotate(self, angle: int, expand: bool = False):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 旋转图片
|
||||
参数:
|
||||
参数:
|
||||
:param angle: 角度
|
||||
:param expand: 放大图片适应角度
|
||||
"""
|
||||
@@ -734,9 +734,9 @@ class BuildImage:
|
||||
|
||||
def rotate(self, angle: int, expand: bool = False):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
旋转图片
|
||||
参数:
|
||||
参数:
|
||||
:param angle: 角度
|
||||
:param expand: 放大图片适应角度
|
||||
"""
|
||||
@@ -744,27 +744,27 @@ class BuildImage:
|
||||
|
||||
async def atranspose(self, angle: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 旋转图片(包括边框)
|
||||
参数:
|
||||
参数:
|
||||
:param angle: 角度
|
||||
"""
|
||||
await self.loop.run_in_executor(None, self.transpose, angle)
|
||||
|
||||
def transpose(self, angle: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
旋转图片(包括边框)
|
||||
参数:
|
||||
参数:
|
||||
:param angle: 角度
|
||||
"""
|
||||
self.markImg.transpose(angle)
|
||||
|
||||
async def afilter(self, filter_: str, aud: int = None):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 图片变化
|
||||
参数:
|
||||
参数:
|
||||
:param filter_: 变化效果
|
||||
:param aud: 利率
|
||||
"""
|
||||
@@ -772,9 +772,9 @@ class BuildImage:
|
||||
|
||||
def filter(self, filter_: str, aud: int = None):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
图片变化
|
||||
参数:
|
||||
参数:
|
||||
:param filter_: 变化效果
|
||||
:param aud: 利率
|
||||
"""
|
||||
@@ -804,9 +804,9 @@ class BuildImage:
|
||||
replace_color: Tuple[int, int, int],
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
异步 颜色替换
|
||||
参数:
|
||||
参数:
|
||||
:param src_color: 目标颜色,或者使用列表,设置阈值
|
||||
:param replace_color: 替换颜色
|
||||
"""
|
||||
@@ -822,9 +822,9 @@ class BuildImage:
|
||||
replace_color: Tuple[int, int, int],
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
颜色替换
|
||||
参数:
|
||||
参数:
|
||||
:param src_color: 目标颜色,或者使用元祖,设置阈值
|
||||
:param replace_color: 替换颜色
|
||||
"""
|
||||
@@ -880,9 +880,9 @@ class BuildMat:
|
||||
bar_color: Optional[List[Union[str, Tuple[int, int, int]]]] = None,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
初始化 BuildMat
|
||||
参数:
|
||||
参数:
|
||||
:param y: 坐标值
|
||||
:param mat_type: 图像类型 可能的值:[line]: 折线图,[bar]: 柱状图,[barh]: 横向柱状图
|
||||
:param x_name: 横坐标名称
|
||||
@@ -981,7 +981,7 @@ class BuildMat:
|
||||
"""
|
||||
说明:
|
||||
给坐标点设置新值
|
||||
参数:
|
||||
参数:
|
||||
:param y: 坐标点
|
||||
"""
|
||||
self._check_value(y, self.y_index)
|
||||
@@ -991,7 +991,7 @@ class BuildMat:
|
||||
"""
|
||||
说明:
|
||||
设置y轴坐标值
|
||||
参数:
|
||||
参数:
|
||||
:param y_index: y轴坐标值
|
||||
"""
|
||||
self._check_value(self.y, y_index)
|
||||
@@ -999,9 +999,9 @@ class BuildMat:
|
||||
|
||||
def set_title(self, title: str, color: Optional[Union[str, Tuple[int, int, int]]]):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置标题
|
||||
参数:
|
||||
参数:
|
||||
:param title: 标题
|
||||
:param color: 字体颜色
|
||||
"""
|
||||
@@ -1013,9 +1013,9 @@ class BuildMat:
|
||||
self, background: Optional[List[str]], type_: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置背景图片
|
||||
参数:
|
||||
参数:
|
||||
:param background: 图片路径列表
|
||||
:param type_: 填充类型
|
||||
"""
|
||||
@@ -1024,32 +1024,32 @@ class BuildMat:
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
展示图像
|
||||
"""
|
||||
self.markImg.show()
|
||||
|
||||
def pic2bs4(self) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
转base64
|
||||
"""
|
||||
return self.markImg.pic2bs4()
|
||||
|
||||
def resize(self, ratio: float = 0.9):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
调整图像大小
|
||||
参数:
|
||||
参数:
|
||||
:param ratio: 比例
|
||||
"""
|
||||
self.markImg.resize(ratio)
|
||||
|
||||
def save(self, path: Union[str, Path]):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
保存图片
|
||||
参数:
|
||||
参数:
|
||||
:param path: 路径
|
||||
"""
|
||||
self.markImg.save(path)
|
||||
@@ -1063,7 +1063,7 @@ class BuildMat:
|
||||
"""
|
||||
说明:
|
||||
检查值合法性
|
||||
参数:
|
||||
参数:
|
||||
:param y: 坐标值
|
||||
:param y_index: y轴坐标值
|
||||
:param x_index: x轴坐标值
|
||||
@@ -1087,7 +1087,7 @@ class BuildMat:
|
||||
"""
|
||||
说明:
|
||||
生成折线图
|
||||
参数:
|
||||
参数:
|
||||
:param y: 坐标点
|
||||
:param display_num: 显示该点的值
|
||||
"""
|
||||
@@ -1134,9 +1134,9 @@ class BuildMat:
|
||||
is_barh: bool = False,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成柱状图
|
||||
参数:
|
||||
参数:
|
||||
:param y: 坐标值
|
||||
:param display_num: 是否显示数值
|
||||
:param is_barh: 横柱状图
|
||||
@@ -1216,9 +1216,9 @@ class BuildMat:
|
||||
is_grid: bool = False,
|
||||
) -> BuildImage:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
初始化图像,生成xy轴
|
||||
参数:
|
||||
参数:
|
||||
:param x_name: x轴名称
|
||||
:param y_name: y轴名称
|
||||
:param x_index: x轴坐标值
|
||||
@@ -1347,7 +1347,7 @@ async def text2image(
|
||||
_add_height: float = 0,
|
||||
) -> BuildImage:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
解析文本并转为图片
|
||||
使用标签
|
||||
<f> </f>
|
||||
@@ -1359,7 +1359,7 @@ async def text2image(
|
||||
在不在,<f font=YSHaoShenTi-2.ttf font_size=30 font_color=red>HibiKi小姐</f>,
|
||||
你最近还好吗,<f font_size=15 font_color=black>我非常想你</f>,这段时间我非常不好过,
|
||||
<f font_size=25>抽卡抽不到金色</f>,这让我很痛苦
|
||||
参数:
|
||||
参数:
|
||||
:param text: 文本
|
||||
:param auto_parse: 是否自动解析,否则原样发送
|
||||
:param font_size: 普通字体大小
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from typing import Union, Optional
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from ruamel import yaml
|
||||
import ujson as json
|
||||
import copy
|
||||
|
||||
yaml = YAML(typ="safe")
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
class StaticData:
|
||||
@@ -26,16 +27,17 @@ class StaticData:
|
||||
if f.read().strip():
|
||||
raise ValueError(f"{file} 文件加载错误,请检查文件内容格式.")
|
||||
elif file.name.endswith("yaml"):
|
||||
self._data = yaml.load(f)
|
||||
self._data = _yaml.load(f)
|
||||
|
||||
def set(self, key, value):
|
||||
self._data[key] = value
|
||||
self.save()
|
||||
|
||||
def set_module_data(self, module, key, value):
|
||||
def set_module_data(self, module, key, value, auto_save: bool = True):
|
||||
if module in self._data.keys():
|
||||
self._data[module][key] = value
|
||||
self.save()
|
||||
if auto_save:
|
||||
self.save()
|
||||
|
||||
def get(self, key):
|
||||
return self._data.get(key)
|
||||
@@ -51,19 +53,22 @@ class StaticData:
|
||||
return copy.deepcopy(self._data)
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
path = path if path else self.file
|
||||
path = path or self.file
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
if path:
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
json.dump(self._data, f, ensure_ascii=False, indent=4)
|
||||
if path.name.endswith("yaml"):
|
||||
yaml.dump(self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
else:
|
||||
json.dump(self._data, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def reload(self):
|
||||
if self.file.exists():
|
||||
if self.file.name.endswith("json"):
|
||||
self._data: dict = json.load(open(self.file, "r", encoding="utf8"))
|
||||
elif self.file.name.endswith("yaml"):
|
||||
self._data: dict = yaml.load(open(self.file, "r", encoding="utf8"))
|
||||
self._data: dict = _yaml.load(open(self.file, "r", encoding="utf8"))
|
||||
|
||||
def is_exists(self):
|
||||
return self.file.exists()
|
||||
|
||||
@@ -31,9 +31,9 @@ class GroupManager(StaticData):
|
||||
|
||||
def block_plugin(self, module: str, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
锁定插件
|
||||
参数:
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组,None时为超级用户禁用
|
||||
"""
|
||||
@@ -41,9 +41,9 @@ class GroupManager(StaticData):
|
||||
|
||||
def unblock_plugin(self, module: str, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
解锁插件
|
||||
参数:
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
"""
|
||||
@@ -51,27 +51,27 @@ class GroupManager(StaticData):
|
||||
|
||||
def turn_on_group_bot_status(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
开启群bot开关
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
self._set_group_bot_status(group_id, True)
|
||||
|
||||
def shutdown_group_bot_status(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
关闭群bot开关
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
self._set_group_bot_status(group_id, False)
|
||||
|
||||
def check_group_bot_status(self, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检查群聊bot总开关状态
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 说明
|
||||
"""
|
||||
group_id = str(group_id)
|
||||
@@ -86,9 +86,9 @@ class GroupManager(StaticData):
|
||||
|
||||
def set_group_level(self, group_id: int, level: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置群权限
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群组
|
||||
:param level: 权限等级
|
||||
"""
|
||||
@@ -100,9 +100,9 @@ class GroupManager(StaticData):
|
||||
|
||||
def get_plugin_status(self, module: str, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取插件状态
|
||||
参数:
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
"""
|
||||
@@ -116,9 +116,9 @@ class GroupManager(StaticData):
|
||||
|
||||
def get_group_level(self, group_id: int) -> int:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取群等级
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
group_id = str(group_id)
|
||||
@@ -128,18 +128,18 @@ class GroupManager(StaticData):
|
||||
|
||||
def check_group_is_white(self, group_id: int) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测群聊是否在白名单
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
return group_id in self._data["super"]["white_group_list"]
|
||||
|
||||
def add_group_white_list(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
将群聊加入白名单
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id not in self._data["super"]["white_group_list"]:
|
||||
@@ -147,9 +147,9 @@ class GroupManager(StaticData):
|
||||
|
||||
def delete_group_white_list(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
将群聊从白名单中删除
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id in self._data["super"]["white_group_list"]:
|
||||
@@ -157,16 +157,16 @@ class GroupManager(StaticData):
|
||||
|
||||
def get_group_white_list(self) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有群白名单
|
||||
"""
|
||||
return self._data["super"]["white_group_list"]
|
||||
|
||||
def delete_group(self, group_id: int):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除群配置
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
if group_id in self._data["group_manager"]:
|
||||
@@ -177,9 +177,9 @@ class GroupManager(StaticData):
|
||||
|
||||
async def open_group_task(self, group_id: int, task: str):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
开启群被动技能
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
@@ -187,9 +187,9 @@ class GroupManager(StaticData):
|
||||
|
||||
async def close_group_task(self, group_id: int, task: str):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
关闭群被动技能
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
@@ -197,9 +197,9 @@ class GroupManager(StaticData):
|
||||
|
||||
async def check_group_task_status(self, group_id: int, task: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查看群被动技能状态
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能名称
|
||||
"""
|
||||
@@ -214,16 +214,16 @@ class GroupManager(StaticData):
|
||||
|
||||
def get_task_data(self) -> Dict[str, str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取所有被动任务
|
||||
"""
|
||||
return self._task
|
||||
|
||||
async def group_task_status(self, group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
查看群被全部动技能状态
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
x = "[群被动技能]:\n"
|
||||
@@ -236,9 +236,9 @@ class GroupManager(StaticData):
|
||||
|
||||
async def _set_group_task_status(self, group_id: int, task: str, status: bool):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
管理群被动技能状态
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param task: 被动技能
|
||||
:param status: 状态
|
||||
@@ -257,7 +257,7 @@ class GroupManager(StaticData):
|
||||
|
||||
async def init_group_task(self, group_id: Optional[Union[int, str]] = None):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
初始化群聊 被动技能 状态
|
||||
"""
|
||||
if not self._task:
|
||||
@@ -313,9 +313,9 @@ class GroupManager(StaticData):
|
||||
group_id: int,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置功能开关状态
|
||||
参数:
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param status: 功能状态
|
||||
:param group_id: 群组
|
||||
@@ -333,9 +333,9 @@ class GroupManager(StaticData):
|
||||
|
||||
def _init_group(self, group_id: str):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
初始化群数据
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
default_group_level = Config.get_config("group_manager", "DEFAULT_GROUP_LEVEL")
|
||||
@@ -354,9 +354,9 @@ class GroupManager(StaticData):
|
||||
|
||||
def _set_group_bot_status(self, group_id: Union[int, str], status: bool):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置群聊bot总开关
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
:param status: 开关状态
|
||||
"""
|
||||
@@ -368,7 +368,7 @@ class GroupManager(StaticData):
|
||||
|
||||
def get_super_old_data(self) -> Optional[dict]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取旧数据,平时使用请不要调用
|
||||
"""
|
||||
if self._data["super"].get("close_plugins"):
|
||||
|
||||
@@ -2,8 +2,10 @@ from typing import List, Optional, Union, Tuple
|
||||
from .data_class import StaticData
|
||||
from pathlib import Path
|
||||
from ruamel.yaml import YAML
|
||||
from ruamel import yaml
|
||||
|
||||
yaml = YAML(typ="safe")
|
||||
|
||||
_yaml = YAML(typ="safe")
|
||||
|
||||
|
||||
class Plugins2settingsManager(StaticData):
|
||||
@@ -16,7 +18,7 @@ class Plugins2settingsManager(StaticData):
|
||||
super().__init__(None)
|
||||
if file.exists():
|
||||
with open(file, "r", encoding="utf8") as f:
|
||||
self._data = yaml.load(f)
|
||||
self._data = _yaml.load(f)
|
||||
if self._data:
|
||||
if "PluginSettings" in self._data.keys():
|
||||
self._data = (
|
||||
@@ -91,11 +93,19 @@ class Plugins2settingsManager(StaticData):
|
||||
return key
|
||||
return keys
|
||||
|
||||
def save(self, path: Union[str, Path] = None):
|
||||
path = path or self.file
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
if path:
|
||||
with open(path, "w", encoding="utf8") as f:
|
||||
yaml.dump({"PluginSettings": self._data}, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
重载本地数据
|
||||
"""
|
||||
if self.file.exists():
|
||||
with open(self.file, "r", encoding="utf8") as f:
|
||||
self._data: dict = yaml.load(f)
|
||||
self._data: dict = _yaml.load(f)
|
||||
self._data = self._data["PluginSettings"]
|
||||
|
||||
@@ -48,9 +48,9 @@ class PluginsManager(StaticData):
|
||||
self, module: str, group_id: Optional[int] = None, block_type: str = "all"
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
锁定插件
|
||||
参数:
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组,None时为超级用户禁用
|
||||
:param block_type: 限制类型
|
||||
@@ -59,9 +59,9 @@ class PluginsManager(StaticData):
|
||||
|
||||
def unblock_plugin(self, module: str, group_id: Optional[int] = None):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
解锁插件
|
||||
参数:
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param group_id: 群组
|
||||
"""
|
||||
@@ -71,9 +71,9 @@ class PluginsManager(StaticData):
|
||||
self, module: str, block_type: str = "all"
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取插件状态
|
||||
参数:
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param block_type: 限制类型
|
||||
"""
|
||||
@@ -86,9 +86,9 @@ class PluginsManager(StaticData):
|
||||
|
||||
def get_plugin_block_type(self, module: str) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取功能限制类型
|
||||
参数:
|
||||
参数:
|
||||
:param module: 模块名称
|
||||
"""
|
||||
if module in self._data.keys():
|
||||
@@ -112,9 +112,9 @@ class PluginsManager(StaticData):
|
||||
block_type: str = "all",
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
设置功能开关状态
|
||||
参数:
|
||||
参数:
|
||||
:param module: 功能模块名
|
||||
:param status: 功能状态
|
||||
:param group_id: 群组
|
||||
|
||||
@@ -8,9 +8,9 @@ class WithdrawMessageManager:
|
||||
|
||||
def append(self, message_data: Tuple[Union[int, Dict[str, int]], int]):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
添加一个撤回消息id和时间
|
||||
参数:
|
||||
参数:
|
||||
:param message_data: 撤回消息id和时间
|
||||
"""
|
||||
if isinstance(message_data[0], dict):
|
||||
@@ -19,9 +19,9 @@ class WithdrawMessageManager:
|
||||
|
||||
def remove(self, message_data: Tuple[int, int]):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
删除一个数据
|
||||
参数:
|
||||
参数:
|
||||
:param message_data: 消息id和时间
|
||||
"""
|
||||
self.data.remove(message_data)
|
||||
|
||||
+28
-26
@@ -13,10 +13,10 @@ def image(
|
||||
b64: str = None,
|
||||
) -> Union[MessageSegment, str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.image 消息
|
||||
生成顺序:绝对路径(abspath) > base64(b64) > img_name
|
||||
参数:
|
||||
参数:
|
||||
:param file: 图片文件名称,默认在 resource/img 目录下
|
||||
:param path: 图片所在路径,默认在 resource/img 目录下
|
||||
:param b64: 图片base64
|
||||
@@ -42,11 +42,11 @@ def image(
|
||||
return ""
|
||||
|
||||
|
||||
def at(qq: int) -> MessageSegment:
|
||||
def at(qq: Union[int, str]) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.at 消息
|
||||
参数:
|
||||
参数:
|
||||
:param qq: qq号
|
||||
"""
|
||||
return MessageSegment.at(qq)
|
||||
@@ -54,9 +54,9 @@ def at(qq: int) -> MessageSegment:
|
||||
|
||||
def record(voice_name: str, path: str = None) -> MessageSegment or str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.record 消息
|
||||
参数:
|
||||
参数:
|
||||
:param voice_name: 音频文件名称,默认在 resource/voice 目录下
|
||||
:param path: 音频文件路径,默认在 resource/voice 目录下
|
||||
"""
|
||||
@@ -79,9 +79,9 @@ def record(voice_name: str, path: str = None) -> MessageSegment or str:
|
||||
|
||||
def text(msg: str) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.text 消息
|
||||
参数:
|
||||
参数:
|
||||
:param msg: 消息文本
|
||||
"""
|
||||
return MessageSegment.text(msg)
|
||||
@@ -89,9 +89,9 @@ def text(msg: str) -> MessageSegment:
|
||||
|
||||
def contact_user(qq: int) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.contact_user 消息
|
||||
参数:
|
||||
参数:
|
||||
:param qq: qq号
|
||||
"""
|
||||
return MessageSegment.contact_user(qq)
|
||||
@@ -101,9 +101,9 @@ def share(
|
||||
url: str, title: str, content: str = None, image_url: str = None
|
||||
) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.share 消息
|
||||
参数:
|
||||
参数:
|
||||
:param url: 自定义分享的链接
|
||||
:param title: 自定义分享的包体
|
||||
:param content: 自定义分享的内容
|
||||
@@ -114,9 +114,9 @@ def share(
|
||||
|
||||
def xml(data: str) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.xml 消息
|
||||
参数:
|
||||
参数:
|
||||
:param data: 数据文本
|
||||
"""
|
||||
return MessageSegment.xml(data)
|
||||
@@ -124,9 +124,9 @@ def xml(data: str) -> MessageSegment:
|
||||
|
||||
def json(data: str) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.json 消息
|
||||
参数:
|
||||
参数:
|
||||
:param data: 消息数据
|
||||
"""
|
||||
return MessageSegment.json(data)
|
||||
@@ -134,9 +134,9 @@ def json(data: str) -> MessageSegment:
|
||||
|
||||
def face(id_: int) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.face 消息
|
||||
参数:
|
||||
参数:
|
||||
:param id_: 表情id
|
||||
"""
|
||||
return MessageSegment.face(id_)
|
||||
@@ -144,9 +144,9 @@ def face(id_: int) -> MessageSegment:
|
||||
|
||||
def poke(qq: int) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
生成一个 MessageSegment.poke 消息
|
||||
参数:
|
||||
参数:
|
||||
:param qq: qq号
|
||||
"""
|
||||
return MessageSegment("poke", {"qq": qq})
|
||||
@@ -157,13 +157,15 @@ def music(type_: str, id_: int) -> MessageSegment:
|
||||
|
||||
|
||||
def custom_forward_msg(
|
||||
msg_list: List[str], uin: Union[int, str], name: str = f"这里是{NICKNAME}"
|
||||
msg_list: List[Union[str, Message]], uin: Union[int, str], name: str = f"这里是{NICKNAME}"
|
||||
) -> List[dict]:
|
||||
"""
|
||||
生成自定义合并消息
|
||||
:param msg_list: 消息列表
|
||||
:param uin: 发送者 QQ
|
||||
:param name: 自定义名称
|
||||
说明:
|
||||
生成自定义合并消息
|
||||
参数:
|
||||
:param msg_list: 消息列表
|
||||
:param uin: 发送者 QQ
|
||||
:param name: 自定义名称
|
||||
"""
|
||||
uin = int(uin)
|
||||
mes_list = []
|
||||
|
||||
+29
-29
@@ -150,9 +150,9 @@ class DailyNumberLimiter:
|
||||
|
||||
def is_number(s: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
检测 s 是否为数字
|
||||
参数:
|
||||
参数:
|
||||
:param s: 文本
|
||||
"""
|
||||
try:
|
||||
@@ -172,7 +172,7 @@ def is_number(s: str) -> bool:
|
||||
|
||||
def get_bot() -> Optional[Bot]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取 bot 对象
|
||||
"""
|
||||
try:
|
||||
@@ -194,9 +194,9 @@ def get_matchers() -> List[Type[Matcher]]:
|
||||
|
||||
def get_message_at(data: Union[str, Message]) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取消息中所有的 at 对象的 qq
|
||||
参数:
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
qq_list = []
|
||||
@@ -214,9 +214,9 @@ def get_message_at(data: Union[str, Message]) -> List[int]:
|
||||
|
||||
def get_message_img(data: Union[str, Message]) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取消息中所有的 图片 的链接
|
||||
参数:
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
img_list = []
|
||||
@@ -233,9 +233,9 @@ def get_message_img(data: Union[str, Message]) -> List[str]:
|
||||
|
||||
def get_message_img_file(data: Union[str, Message]) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取消息中所有的 图片file
|
||||
参数:
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
file_list = []
|
||||
@@ -252,9 +252,9 @@ def get_message_img_file(data: Union[str, Message]) -> List[str]:
|
||||
|
||||
def get_message_text(data: Union[str, Message]) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取消息中 纯文本 的信息
|
||||
参数:
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
result = ""
|
||||
@@ -267,14 +267,14 @@ def get_message_text(data: Union[str, Message]) -> str:
|
||||
else:
|
||||
for seg in data["text"]:
|
||||
result += seg.data["text"] + " "
|
||||
return result
|
||||
return result.strip()
|
||||
|
||||
|
||||
def get_message_record(data: Union[str, Message]) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取消息中所有 语音 的链接
|
||||
参数:
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
record_list = []
|
||||
@@ -291,9 +291,9 @@ def get_message_record(data: Union[str, Message]) -> List[str]:
|
||||
|
||||
def get_message_json(data: str) -> List[dict]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取消息中所有 json
|
||||
参数:
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
try:
|
||||
@@ -309,7 +309,7 @@ def get_message_json(data: str) -> List[dict]:
|
||||
|
||||
def get_local_proxy():
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
获取 config.py 中设置的代理
|
||||
"""
|
||||
return SYSTEM_PROXY if SYSTEM_PROXY else None
|
||||
@@ -317,9 +317,9 @@ def get_local_proxy():
|
||||
|
||||
def is_chinese(word: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
判断字符串是否为纯中文
|
||||
参数:
|
||||
参数:
|
||||
:param word: 文本
|
||||
"""
|
||||
for ch in word:
|
||||
@@ -330,9 +330,9 @@ def is_chinese(word: str) -> bool:
|
||||
|
||||
async def get_user_avatar(qq: int) -> Optional[bytes]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
快捷获取用户头像
|
||||
参数:
|
||||
参数:
|
||||
:param qq: qq号
|
||||
"""
|
||||
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=160"
|
||||
@@ -347,9 +347,9 @@ async def get_user_avatar(qq: int) -> Optional[bytes]:
|
||||
|
||||
async def get_group_avatar(group_id: int) -> Optional[bytes]:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
快捷获取用群头像
|
||||
参数:
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
url = f"http://p.qlogo.cn/gh/{group_id}/{group_id}/640/"
|
||||
@@ -364,9 +364,9 @@ async def get_group_avatar(group_id: int) -> Optional[bytes]:
|
||||
|
||||
def cn2py(word: str) -> str:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
将字符串转化为拼音
|
||||
参数:
|
||||
参数:
|
||||
:param word: 文本
|
||||
"""
|
||||
temp = ""
|
||||
@@ -379,9 +379,9 @@ def change_pixiv_image_links(
|
||||
url: str, size: Optional[str] = None, nginx_url: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
根据配置改变图片大小和反代链接
|
||||
参数:
|
||||
参数:
|
||||
:param url: 图片原图链接
|
||||
:param size: 模式
|
||||
:param nginx_url: 反代
|
||||
@@ -404,9 +404,9 @@ def change_pixiv_image_links(
|
||||
|
||||
def change_img_md5(path_file: Union[str, Path]) -> bool:
|
||||
"""
|
||||
说明:
|
||||
说明:
|
||||
改变图片MD5
|
||||
参数:
|
||||
参数:
|
||||
:param path_file: 图片路径
|
||||
"""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user