Compare commits

..
25 Commits
Author SHA1 Message Date
HibiKier d6110e3c6f update bilibili_sub 2022-07-03 22:00:49 +08:00
HibiKier 4c5302bd4c fix shop update goods 2022-07-03 16:47:19 +08:00
HibiKier 21ee3d5c3e update send_setu 2022-07-03 16:33:14 +08:00
HibiKier e5c036cee8 update shop image 2022-07-03 13:55:26 +08:00
HibiKier 6f82488af7 Merge pull request #879 from VirtualTowel/main
修复图库内图片无法被连续删除的问题
2022-07-03 13:53:49 +08:00
VirtualTowel 57a7903c63 修复图库内图片无法被连续删除的问题 2022-07-01 20:12:39 +08:00
HibiKier 27b89b333a Merge pull request #866 from Excalibur5100/main
修复色图插件api修改无法搜索图片
2022-06-28 20:48:33 +08:00
Excalibur5100 ce2c4e7492 修复色图插件最近加tag参数后搜不到图的问题
插件所用API更新,最大数量num改为20
https://api.lolicon.app/#/setu
2022-06-28 19:48:59 +08:00
HibiKier cad98a2a33 Update goods_info.py 2022-06-26 22:23:19 +08:00
HibiKier 40da48e685 update models 2022-06-26 19:29:51 +08:00
HibiKier 1c393e5c3e update shop daily_limit 2022-06-26 03:08:23 +08:00
HibiKier 667c143c74 update pix 2022-06-26 01:37:47 +08:00
HibiKier bc089c18ce update bt 2022-06-26 01:26:14 +08:00
HibiKier 24b730c0e2 Merge pull request #847 from po-lan/main
对WSL虚拟机 代理 添加写法
2022-06-24 20:59:28 +08:00
po-lan 9ed9e9b973 对WSL虚拟机 代理 添加写法 2022-06-23 17:57:47 +08:00
HibiKier 5b0027aa3d Update README.md 2022-06-22 22:49:26 +08:00
HibiKier 810c5e4e8b Update README.md 2022-06-21 21:59:41 +08:00
HibiKier 907534958f Merge pull request #840 from yajiwa/main
update parse_bilibili
2022-06-21 21:59:23 +08:00
HibiKier f08a18ab07 Update data_class.py 2022-06-21 21:01:14 +08:00
github-actions[bot] 40549d5ca7 Auto generate poetry.lock 2022-06-21 00:56:57 +00:00
yajiwa 3e67edc506 update pyproject.toml 2022-06-21 08:53:49 +08:00
yajiwa 9c56a81f65 update parse_bilibili 2022-06-21 08:50:05 +08:00
HibiKier a9a636c9ae Update plugins2settings_manager.py 2022-06-20 22:31:57 +08:00
HibiKier 98374dcd74 Update README.md 2022-06-20 22:07:48 +08:00
HibiKier 10ca6eec91 update webui 2022-06-20 21:54:10 +08:00
29 changed files with 863 additions and 941 deletions
+31 -1
View File
@@ -243,6 +243,33 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
## 更新
### 2022/7/3
* 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为字符串
@@ -654,10 +681,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
View File
@@ -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
+8
View File
@@ -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:
+4
View File
@@ -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,
+15 -3
View File
@@ -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}")
+102 -38
View File
@@ -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
+5
View File
@@ -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 # 全局代理
+1 -1
View File
@@ -209,7 +209,7 @@ 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"]:
+93 -26
View File
@@ -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,17 +12,22 @@ 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:
"""
说明:
@@ -33,6 +38,7 @@ class GoodsInfo(db.Model):
: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:
@@ -58,8 +65,8 @@ class GoodsInfo(db.Model):
"""
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,12 +75,13 @@ 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:
"""
说明:
@@ -84,27 +92,27 @@ class GoodsInfo(db.Model):
: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":
@@ -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:
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()
+25 -7
View File
@@ -1,4 +1,6 @@
from bilireq.exceptions import ResponseCodeError
from nonebot.adapters.onebot.v11 import MessageSegment
from utils.manager import resources_manager
from asyncio.exceptions import TimeoutError
from .model import BilibiliSub
@@ -8,7 +10,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
@@ -304,7 +306,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]:
"""
获取用户动态
:param uid: 用户uid
@@ -317,14 +319,15 @@ async def get_user_dynamic(
if dynamic_info.get("cards") and browser:
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
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",
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(
"""
@@ -334,15 +337,30 @@ async def get_user_dynamic(
}
"""
)
card = page.locator(".bili-dyn-list__item").first
async with page.expect_popup() as popup_info:
await page.locator(".bili-rich-text__content").click()
details_page = await popup_info.value
await details_page.set_viewport_size(
{"width": 2560, "height": 1080, "timeout": 10000 * 20}
)
await details_page.wait_for_selector(".panel-area")
await details_page.evaluate(
"""
xs = document.getElementById('internationalHeader');
xs.remove();
xs = document.getElementsByClassName('panel-area')
xs[0].remove();
"""
)
card = details_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(
@@ -351,7 +369,7 @@ async def get_user_dynamic(
),
dynamic_upload_time,
)
return None, None
return None, 0
class SubManager:
+1 -1
View File
@@ -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):
@@ -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}")
+164 -165
View File
@@ -1,165 +1,164 @@
# 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"],
proxy=get_local_proxy(),
timeout=7,
) as response:
url = str(response.url).split("?")[0]
bvid = url.split("/")[-1]
vd_info = await video.get_video_base_info(bvid)
# 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.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") + 13]
res = await AsyncHttpx.get(url, timeout=7)
url = str(res.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)
+1
View File
@@ -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
+51 -23
View File
@@ -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,
@@ -300,27 +307,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")
)
+1 -1
View File
@@ -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):
+6
View File
@@ -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()
Generated
+276 -646
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -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
View File
@@ -10,7 +10,8 @@
"poetry.lock",
"pyproject.toml",
"resources/font",
"bot.py"
"resources/image/zhenxun",
"resources/image/other"
],
"add_file": [],
"delete_file": []
+2 -7
View File
@@ -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
+30 -4
View File
@@ -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
+15 -1
View File
@@ -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
@@ -135,6 +135,7 @@ class AsyncHttpx:
:param url: url
:param path: 存储路径
:param params: params
:param verify: verify
:param use_proxy: 使用代理
:param proxy: 指定代理
:param headers: 请求头
@@ -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,
+12 -7
View File
@@ -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()
+13 -3
View File
@@ -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"]
+1 -1
View File
@@ -157,7 +157,7 @@ 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]:
"""
生成自定义合并消息