Merge branch 'main' into main

This commit is contained in:
HibiKier
2023-02-18 22:56:25 +08:00
committed by GitHub
138 changed files with 5649 additions and 6249 deletions
+14 -15
View File
@@ -1,20 +1,20 @@
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from nonebot import on_command
from nonebot.rule import to_me
import os
import random
from nonebot import on_command, on_keyword
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.utils import FreqLimiter
from configs.config import NICKNAME
import random
from nonebot import on_keyword
import os
from nonebot.rule import to_me
from configs.config import NICKNAME
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from utils.utils import FreqLimiter
__zx_plugin_name__ = "基本设置 [Hidden]"
__plugin_usage__ = "用法: 无"
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_author__ = "HibiKier"
_flmt = FreqLimiter(300)
@@ -29,7 +29,7 @@ async def _(event: GroupMessageEvent):
return
_flmt.start_cd(event.group_id)
await config_play_game.finish(
image(random.choice(os.listdir(IMAGE_PATH / "dayouxi")), "dayouxi")
image(IMAGE_PATH / random.choice(os.listdir(IMAGE_PATH / "dayouxi")))
)
@@ -40,14 +40,14 @@ self_introduction = on_command(
@self_introduction.handle()
async def _():
if NICKNAME.find('真寻') != -1:
if NICKNAME.find("真寻") != -1:
result = (
"我叫绪山真寻\n"
"你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n"
"年龄的话我还是个**岁初中生(至少现在是)\n"
"身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n"
"我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n"
"最好的朋友是椛!\n" + image("zhenxun")
"最好的朋友是椛!\n" + image("zhenxun.jpg")
)
await self_introduction.finish(result)
@@ -57,5 +57,4 @@ my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True)
@my_wife.handle()
async def _():
await my_wife.finish(image("laopo.jpg", "other"))
await my_wife.finish(image(IMAGE_PATH / "other" / "laopo.jpg"))
+6 -12
View File
@@ -1,18 +1,14 @@
from nonebot import on_message
from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
Message,
MessageEvent,
)
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.rule import to_me
from configs.config import NICKNAME, Config
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.utils import get_message_img, get_message_text
from .data_source import get_chat_result, hello, no_result
from configs.config import NICKNAME, Config
__zx_plugin_name__ = "AI"
__plugin_usage__ = f"""
@@ -61,11 +57,9 @@ async def _(bot: Bot, event: MessageEvent):
await ai.finish(hello())
img = img[0] if img else ""
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
nickname = await GroupInfoUser.get_user_nickname(event.user_id, event.group_id)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
nickname = await FriendUser.get_user_nickname(event.user_id)
if not nickname:
if isinstance(event, GroupMessageEvent):
nickname = event.sender.card or event.sender.nickname
+21 -18
View File
@@ -1,11 +1,13 @@
import os
import random
import re
from utils.http_utils import AsyncHttpx
from configs.path_config import IMAGE_PATH, DATA_PATH
from configs.config import NICKNAME, Config
from configs.path_config import DATA_PATH, IMAGE_PATH
from services.log import logger
from utils.message_builder import image, face
from configs.config import Config, NICKNAME
from utils.http_utils import AsyncHttpx
from utils.message_builder import face, image
from .utils import ai_message_manager
try:
@@ -124,7 +126,9 @@ async def xie_ai(text: str) -> str:
:param text: 问题
:return: 青云可回复
"""
res = await AsyncHttpx.get(f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}")
res = await AsyncHttpx.get(
f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}"
)
content = ""
try:
data = json.loads(res.text)
@@ -176,9 +180,9 @@ def hello() -> str:
)
img = random.choice(os.listdir(IMAGE_PATH / "zai"))
if img[-4:] == ".gif":
result += image(img, "zai")
result += image(IMAGE_PATH / "zai" / img)
else:
result += image(img, "zai")
result += image(IMAGE_PATH / "zai" / img)
return result
@@ -187,17 +191,16 @@ def no_result() -> str:
"""
没有回答时的回复
"""
return (
random.choice(
[
"你在说啥子?",
f"纯洁的{NICKNAME}没听懂",
"下次再告诉你(下次一定)",
"你觉得我听懂了吗?嗯?",
"我!不!知!道!",
]
)
+ image(random.choice(os.listdir(IMAGE_PATH / "noresult")), "noresult")
return random.choice(
[
"你在说啥子?",
f"纯洁的{NICKNAME}没听懂",
"下次再告诉你(下次一定)",
"你觉得我听懂了吗?嗯?",
"我!不!知!道!",
]
) + image(
IMAGE_PATH / "noresult" / random.choice(os.listdir(IMAGE_PATH / "noresult"))
)
+32 -31
View File
@@ -1,28 +1,29 @@
from nonebot import on_command, on_regex
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from typing import Any, Optional, Tuple
import nonebot
from nonebot import Driver, on_command, on_regex
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import ArgStr, CommandArg, RegexGroup
from nonebot.typing import T_State
from configs.config import Config
from models.level_user import LevelUser
from services.log import logger
from utils.image_utils import text2image
from utils.manager import group_manager
from utils.message_builder import image
from utils.utils import get_bot, is_number, scheduler
from .data_source import (
BilibiliSub,
SubManager,
add_live_sub,
delete_sub,
add_up_sub,
add_season_sub,
add_up_sub,
delete_sub,
get_media_id,
get_sub_status,
SubManager,
BilibiliSub,
)
from models.level_user import LevelUser
from utils.manager import group_manager
from configs.config import Config
from utils.utils import is_number, scheduler, get_bot
from typing import Optional, Tuple, Any
from services.log import logger
from nonebot import Driver
from nonebot.params import CommandArg, ArgStr, RegexGroup
import nonebot
__zx_plugin_name__ = "B站订阅"
__plugin_usage__ = """
@@ -168,20 +169,20 @@ async def _(
sub_user: str = ArgStr("sub_user"),
):
if sub_type in ["主播", "直播"]:
result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user,"live")
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user, "live")
elif sub_type.lower() in ["up", "用户"]:
result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user,"up")
else: result = await BilibiliSub.delete_bilibili_sub(int(id_),sub_user)
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user, "up")
else:
result = await BilibiliSub.delete_bilibili_sub(int(id_), sub_user)
if result:
await del_sub.send(f"删除订阅id:{id_} 成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除订阅 {id_}"
)
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除订阅 {id_}"
)
else:
await del_sub.send(f"删除订阅id:{id_} 失败...")
@show_sub_info.handle()
@@ -190,7 +191,7 @@ async def _(event: MessageEvent):
id_ = f"{event.group_id}"
else:
id_ = f"{event.user_id}"
data = await BilibiliSub.get_sub_data(id_)
data = await BilibiliSub.filter(sub_users__contains=id_).all()
live_rst = ""
up_rst = ""
season_rst = ""
@@ -217,11 +218,9 @@ async def _(event: MessageEvent):
)
await show_sub_info.send(
image(
b64=(
await text2image(
live_rst + up_rst + season_rst, padding=10, color="#f9f6f2"
)
).pic2bs4()
await text2image(
live_rst + up_rst + season_rst, padding=10, color="#f9f6f2"
)
)
)
@@ -277,7 +276,9 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
):
rst = "[CQ:at,qq=all]\n" + rst
if group_manager.get_plugin_status("bilibili_sub", group_id):
await bot.send_group_msg(group_id=group_id, message=Message(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:
+98 -138
View File
@@ -1,34 +1,33 @@
from bilireq.exceptions import ResponseCodeError
from nonebot.adapters.onebot.v11 import MessageSegment
from utils.manager import resources_manager
import random
from asyncio.exceptions import TimeoutError
from datetime import datetime
from typing import Optional, Tuple
from utils.utils import get_bot
from .model import BilibiliSub
from bilireq.live import get_room_info_by_id
from .utils import get_meta, get_user_card
from utils.message_builder import image
from bilireq.user import get_videos
# from .utils import get_videos
from bilireq import dynamic
from typing import Optional, Tuple
from configs.path_config import IMAGE_PATH
from datetime import datetime
from utils.browser import get_browser
from services.db_context import db
from bilireq.exceptions import ResponseCodeError
from bilireq.live import get_room_info_by_id
from bilireq.user import get_videos
from nonebot.adapters.onebot.v11 import MessageSegment
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
import random
from utils.browser import get_browser
from utils.http_utils import AsyncHttpx, AsyncPlaywright
from utils.manager import resources_manager
from utils.message_builder import image
from utils.utils import get_bot
from .model import BilibiliSub
from .utils import get_meta, get_user_card
SEARCH_URL = "https://api.bilibili.com/x/web-interface/search/all/v2"
DYNAMIC_PATH = IMAGE_PATH / "bilibili_sub" / "dynamic"
DYNAMIC_PATH.mkdir(exist_ok=True, parents=True)
bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2"
dynamic_path = IMAGE_PATH / "bilibili_sub" / "dynamic"
dynamic_path.mkdir(exist_ok=True, parents=True)
resources_manager.add_temp_dir(dynamic_path)
resources_manager.add_temp_dir(DYNAMIC_PATH)
async def add_live_sub(live_id: int, sub_user: str) -> str:
@@ -49,7 +48,7 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
short_id = live_info["short_id"]
title = live_info["title"]
live_status = live_info["live_status"]
if await BilibiliSub.add_bilibili_sub(
if await BilibiliSub.sub_handle(
room_id,
"live",
sub_user,
@@ -58,14 +57,14 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
live_status=live_status,
):
await _get_up_status(room_id)
uname = (await BilibiliSub.get_sub(room_id)).uname
uname = (await BilibiliSub.get_or_none(sub_id=room_id)).uname
return (
"已成功订阅主播:\n"
f"\ttitle:{title}\n"
f"\tname: {uname}\n"
f"\tlive_id:{room_id}\n"
f"\tuid:{uid}"
)
)
else:
return "添加订阅失败..."
except Exception as e:
@@ -80,35 +79,34 @@ async def add_up_sub(uid: int, sub_user: str) -> str:
:param sub_user: 订阅用户
"""
try:
async with db.transaction():
try:
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_card(uid)
except ResponseCodeError:
return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
uname = user_info["name"]
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
dynamic_upload_time = 0
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(uid)
latest_video_created = 0
if video_info["list"].get("vlist"):
latest_video_created = video_info["list"]["vlist"][0]["created"]
if await BilibiliSub.add_bilibili_sub(
uid,
"up",
sub_user,
uid=uid,
uname=uname,
dynamic_upload_time=dynamic_upload_time,
latest_video_created=latest_video_created,
):
return "已成功订阅UP:\n" f"\tname: {uname}\n" f"\tuid:{uid}"
else:
return "添加订阅失败..."
try:
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_card(uid)
except ResponseCodeError:
return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
uname = user_info["name"]
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
dynamic_upload_time = 0
if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
"""bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(uid)
latest_video_created = 0
if video_info["list"].get("vlist"):
latest_video_created = video_info["list"]["vlist"][0]["created"]
if await BilibiliSub.sub_handle(
uid,
"up",
sub_user,
uid=uid,
uname=uname,
dynamic_upload_time=dynamic_upload_time,
latest_video_created=latest_video_created,
):
return "已成功订阅UP:\n" f"\tname: {uname}\n" f"\tuid:{uid}"
else:
return "添加订阅失败..."
except Exception as e:
logger.error(f"订阅Up uid:{uid} 发生了错误 {type(e)}:{e}")
return "添加订阅失败..."
@@ -121,30 +119,29 @@ async def add_season_sub(media_id: int, sub_user: str) -> str:
:param sub_user: 订阅用户
"""
try:
async with db.transaction():
try:
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(media_id)
except ResponseCodeError:
return f"未找到media_id:{media_id} 的信息,请检查Id是否正确"
season_id = season_info["media"]["season_id"]
season_current_episode = season_info["media"]["new_ep"]["index"]
season_name = season_info["media"]["title"]
if await BilibiliSub.add_bilibili_sub(
media_id,
"season",
sub_user,
season_name=season_name,
season_id=season_id,
season_current_episode=season_current_episode,
):
return (
"已成功订阅番剧:\n"
f"\ttitle: {season_name}\n"
f"\tcurrent_episode: {season_current_episode}"
)
else:
return "添加订阅失败..."
try:
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(media_id)
except ResponseCodeError:
return f"未找到media_id:{media_id} 的信息,请检查Id是否正确"
season_id = season_info["media"]["season_id"]
season_current_episode = season_info["media"]["new_ep"]["index"]
season_name = season_info["media"]["title"]
if await BilibiliSub.sub_handle(
media_id,
"season",
sub_user,
season_name=season_name,
season_id=season_id,
season_current_episode=season_current_episode,
):
return (
"已成功订阅番剧:\n"
f"\ttitle: {season_name}\n"
f"\tcurrent_episode: {season_current_episode}"
)
else:
return "添加订阅失败..."
except Exception as e:
logger.error(f"订阅番剧 media_id:{media_id} 发生了错误 {type(e)}:{e}")
return "添加订阅失败..."
@@ -171,9 +168,7 @@ async def get_media_id(keyword: str) -> dict:
for _ in range(3):
try:
_season_data = {}
response = await AsyncHttpx.get(
bilibili_search_url, params=params, timeout=5
)
response = await AsyncHttpx.get(SEARCH_URL, params=params, timeout=5)
if response.status_code == 200:
data = response.json()
if data.get("data"):
@@ -227,9 +222,9 @@ async def _get_live_status(id_: int) -> Optional[str]:
room_id = live_info["room_id"]
live_status = live_info["live_status"]
cover = live_info["user_cover"]
sub = await BilibiliSub.get_sub(id_)
sub = await BilibiliSub.get_or_none(sub_id=id_)
if sub.live_status != live_status:
await BilibiliSub.update_sub_info(id_, live_status=live_status)
await BilibiliSub.sub_handle(id_, live_status=live_status)
if sub.live_status in [0, 2] and live_status == 1:
return (
f""
@@ -247,7 +242,7 @@ async def _get_up_status(id_: int) -> Optional[str]:
:param id_: 订阅 id
:return:
"""
_user = await BilibiliSub.get_sub(id_)
_user = await BilibiliSub.get_or_none(sub_id=id_)
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_card(_user.uid)
uname = user_info["name"]
@@ -257,14 +252,14 @@ async def _get_up_status(id_: int) -> Optional[str]:
video = None
dividing_line = "\n-------------\n"
if _user.uname != uname:
await BilibiliSub.update_sub_info(id_, uname=uname)
await BilibiliSub.sub_handle(id_, uname=uname)
dynamic_img, dynamic_upload_time, link = await get_user_dynamic(_user.uid, _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)
await BilibiliSub.sub_handle(id_, dynamic_upload_time=dynamic_upload_time)
rst += f"{uname} 发布了动态!\n" f"{dynamic_img}\n{link}"
if (
latest_video_created
@@ -273,9 +268,7 @@ async def _get_up_status(id_: int) -> Optional[str]:
and _user.latest_video_created < latest_video_created
):
rst = rst + dividing_line if rst else rst
await BilibiliSub.update_sub_info(
id_, latest_video_created=latest_video_created
)
await BilibiliSub.sub_handle(id_, latest_video_created=latest_video_created)
rst += (
f'{image(video["pic"])}\n'
f"{uname} 投稿了新视频啦\n"
@@ -295,10 +288,10 @@ async def _get_season_status(id_) -> Optional[str]:
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(id_)
title = season_info["media"]["title"]
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode
_idx = (await BilibiliSub.get_or_none(sub_id=id_)).season_current_episode
new_ep = season_info["media"]["new_ep"]["index"]
if new_ep != _idx:
await BilibiliSub.update_sub_info(
await BilibiliSub.sub_handle(
id_, season_current_episode=new_ep, season_update_time=datetime.now()
)
return (
@@ -320,55 +313,22 @@ async def get_user_dynamic(
"""
"""bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
browser = await get_browser()
if dynamic_info.get("cards") and browser:
if dynamic_info.get("cards"):
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:
context = await browser.new_context()
page = await context.new_page()
try:
await page.goto(
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.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(".bili-dyn-item__main")
card = page.locator(".bili-dyn-item__main")
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(
f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
"bilibili_sub/dynamic",
),
dynamic_upload_time,
f"https://t.bilibili.com/{dynamic_id}"
image = await AsyncPlaywright.screenshot(
f"https://t.bilibili.com/{dynamic_id}",
DYNAMIC_PATH / f"sub_{local_user.sub_id}.png",
".bili-dyn-item__main",
wait_until="networkidle",
)
return None, 0, ''
return (
image,
dynamic_upload_time,
f"https://t.bilibili.com/{dynamic_id}",
)
return None, 0, ""
class SubManager:
+112 -186
View File
@@ -1,43 +1,58 @@
from services.log import logger
from services.db_context import db
from datetime import datetime
from typing import Optional, List
from typing import List, Optional, Tuple
from tortoise import fields
from services.db_context import Model
from services.log import logger
class BilibiliSub(db.Model):
__tablename__ = "bilibili_sub"
class BilibiliSub(Model):
id = db.Column(db.Integer(), primary_key=True)
sub_id = db.Column(db.Integer(), nullable=False)
sub_type = db.Column(db.String(), nullable=False)
# 订阅用户
sub_users = db.Column(db.String(), nullable=False)
# 直播
live_short_id = db.Column(db.Integer())
live_status = db.Column(db.Integer)
# 主播/UP
uid = db.Column(db.BigInteger())
uname = db.Column(db.String())
latest_video_created = db.Column(db.BigInteger()) # 视频上传时间
dynamic_upload_time = db.Column(db.BigInteger(), default=0) # 动态发布时间
# 番剧
season_name = db.Column(db.String())
season_id = db.Column(db.Integer())
season_current_episode = db.Column(db.String())
season_update_time = db.Column(db.DateTime())
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
sub_id = fields.IntField()
"""订阅id"""
sub_type = fields.CharField(255)
"""订阅类型"""
sub_users = fields.TextField()
"""订阅用户"""
live_short_id = fields.IntField(null=True)
"""直播短id"""
live_status = fields.IntField(null=True)
"""直播状态 0: 停播 1: 直播"""
uid = fields.BigIntField(null=True)
"""主播/UP UID"""
uname = fields.CharField(255, null=True)
"""主播/UP 名称"""
latest_video_created = fields.BigIntField(null=True)
"""最后视频上传时间"""
dynamic_upload_time = fields.BigIntField(null=True, default=0)
"""动态发布时间"""
season_name = fields.CharField(255, null=True)
"""番剧名称"""
season_id = fields.IntField(null=True)
"""番剧id"""
season_current_episode = fields.CharField(255, null=True)
"""番剧最新集数"""
season_update_time = fields.DateField(null=True)
"""番剧更新日期"""
_idx1 = db.Index("bilibili_sub_idx1", "sub_id", "sub_type", unique=True)
class Meta:
table = "bilibili_sub"
table_description = "B站订阅数据表"
unique_together = ("sub_id", "sub_type")
@classmethod
async def add_bilibili_sub(
async def sub_handle(
cls,
sub_id: int,
sub_type: str,
sub_user: str,
sub_type: Optional[str] = None,
sub_user: str = "",
*,
live_short_id: Optional[int] = None,
live_status: Optional[int] = None,
dynamic_upload_time: Optional[int] = None,
dynamic_upload_time: int = 0,
uid: Optional[int] = None,
uname: Optional[str] = None,
latest_video_created: Optional[int] = None,
@@ -64,50 +79,60 @@ class BilibiliSub(db.Model):
:param season_current_episode: 番剧最新集数
:param season_update_time: 番剧更新时间
"""
try:
query = (
await cls.query.where( (cls.sub_id == sub_id) & (cls.sub_type == sub_type) )
.with_for_update()
.gino.first()
)
# try:
data = {
"sub_type": sub_type,
"sub_user": sub_user,
"live_short_id": live_short_id,
"live_status": live_status,
"dynamic_upload_time": dynamic_upload_time,
"uid": uid,
"uname": uname,
"latest_video_created": latest_video_created,
"season_name": season_name,
"season_id": season_id,
"season_current_episode": season_current_episode,
"season_update_time": season_update_time,
}
if sub_user:
sub_user = sub_user if sub_user[-1] == "," else f"{sub_user},"
if query:
if sub_user not in query.sub_users:
sub_users = query.sub_users + sub_user
await query.update(sub_users=sub_users).apply()
else:
sub = await cls.create(
sub_id=sub_id, sub_type=sub_type, sub_users=sub_user
)
await sub.update(
live_short_id=live_short_id
if live_short_id
else sub.live_short_id,
live_status=live_status if live_status else sub.live_status,
dynamic_upload_time=dynamic_upload_time
if dynamic_upload_time
else sub.dynamic_upload_time,
uid=uid if uid else sub.uid,
uname=uname if uname else sub.uname,
latest_video_created=latest_video_created
if latest_video_created
else sub.latest_video_created,
season_update_time=season_update_time
if season_update_time
else sub.season_update_time,
season_current_episode=season_current_episode
if season_current_episode
else sub.season_current_episode,
season_id=season_id if season_id else sub.season_id,
season_name=season_name if season_name else sub.season_name,
).apply()
return True
except Exception as e:
logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}")
return False
sub = None
if sub_type:
sub = await cls.get_or_none(sub_id=sub_id, sub_type=sub_type)
else:
sub = await cls.get_or_none(sub_id=sub_id)
if sub:
sub_users = sub.sub_users + sub_user
data["sub_type"] = sub_type or sub.sub_type
data["sub_user"] = sub_users
data["live_short_id"] = live_short_id or sub.live_short_id
data["live_status"] = (
live_status if live_status is not None else sub.live_status
)
data["dynamic_upload_time"] = dynamic_upload_time or sub.dynamic_upload_time
data["uid"] = uid or sub.uid
data["uname"] = uname or sub.uname
data["latest_video_created"] = (
latest_video_created or sub.latest_video_created
)
data["season_name"] = season_name or sub.season_name
data["season_id"] = season_id or sub.season_id
data["season_current_episode"] = (
season_current_episode or sub.season_current_episode
)
data["season_update_time"] = season_update_time or sub.season_update_time
else:
await cls.create(sub_id=sub_id, sub_type=sub_type, sub_users=sub_user)
await cls.update_or_create(sub_id=sub_id, defaults=data)
return True
# except Exception as e:
# logger.info(f"bilibili_sub 添加订阅错误 {type(e)}: {e}")
# return False
@classmethod
async def delete_bilibili_sub(cls, sub_id: int, sub_user: str,sub_type: Optional[str] = None) -> bool:
async def delete_bilibili_sub(
cls, sub_id: int, sub_user: str, sub_type: Optional[str] = None
) -> bool:
"""
说明:
删除订阅
@@ -116,129 +141,30 @@ class BilibiliSub(db.Model):
:param sub_user: 删除此条目的用户
"""
try:
async with db.transaction():
if sub_type:
query = (
await cls.query.where(
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user) & (cls.sub_type == sub_type))
)
.with_for_update()
.gino.first()
)
else:
query = (
await cls.query.where(
(cls.sub_id == sub_id) & (cls.sub_users.contains(sub_user))
)
.with_for_update()
.gino.first()
)
if not query:
return False
await query.update(
sub_users=query.sub_users.replace(f"{sub_user},", "")
).apply()
if not query.sub_users.strip():
await query.delete()
return True
if sub_type:
sub = await cls.filter(
sub_id=sub_id, sub_type=sub_type, sub_users__contains=sub_user
).first()
else:
sub = await cls.filter(
sub_id=sub_id, sub_users__contains=sub_user
).first()
if not sub:
return False
sub.sub_users = sub.sub_users.replace(f"{sub_user},", "")
if sub.sub_users.strip():
await sub.save(update_fields=["sub_users"])
else:
await sub.delete()
return True
except Exception as e:
logger.info(f"bilibili_sub 删除订阅错误 {type(e)}: {e}")
return False
@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()
@classmethod
async def get_sub_data(cls, id_: str) -> List["BilibiliSub"]:
"""
获取 id_ 订阅的所有内容
:param id_: id
"""
query = cls.query.where(cls.sub_users.contains(id_))
return await query.gino.all()
@classmethod
async def update_sub_info(
cls,
sub_id: int,
*,
live_short_id: Optional[int] = None,
live_status: Optional[int] = None,
dynamic_upload_time: Optional[int] = None,
uid: Optional[int] = None,
uname: Optional[str] = None,
latest_video_created: Optional[int] = None,
season_name: Optional[str] = None,
season_id: Optional[int] = None,
season_current_episode: Optional[str] = None,
season_update_time: Optional[datetime] = None,
) -> bool:
"""
说明:
更新订阅信息
参数:
:param sub_id: 订阅名称,房间号,番剧号等
:param live_short_id: 直接短 id
:param live_status: 主播开播状态
:param dynamic_upload_time: 主播/UP最新动态时间
:param uid: 主播/UP uid
:param uname: 用户名称
:param latest_video_created: 最新视频上传时间
:param season_name: 番剧名称
:param season_id: 番剧 season_id
:param season_current_episode: 番剧最新集数
:param season_update_time: 番剧更新时间
"""
try:
async with db.transaction():
sub = (
await cls.query.where(cls.sub_id == sub_id)
.with_for_update()
.gino.first()
)
if sub:
await sub.update(
live_short_id=live_short_id
if live_short_id is not None
else sub.live_short_id,
live_status=live_status
if live_status is not None
else sub.live_status,
dynamic_upload_time=dynamic_upload_time
if dynamic_upload_time is not None
else sub.dynamic_upload_time,
uid=uid if uid is not None else sub.uid,
uname=uname if uname is not None else sub.uname,
latest_video_created=latest_video_created
if latest_video_created is not None
else sub.latest_video_created,
season_update_time=season_update_time
if season_update_time is not None
else sub.season_update_time,
season_current_episode=season_current_episode
if season_current_episode is not None
else sub.season_current_episode,
season_id=season_id if season_id is not None else sub.season_id,
season_name=season_name
if season_name is not None
else sub.season_name,
).apply()
return True
except Exception as e:
logger.info(f"bilibili_sub 更新订阅错误 {type(e)}: {e}")
return False
@classmethod
async def get_all_sub_data(
cls,
) -> "List[BilibiliSub], List[BilibiliSub], List[BilibiliSub]":
) -> Tuple[List["BilibiliSub"], List["BilibiliSub"], List["BilibiliSub"]]:
"""
说明:
分类获取所有数据
@@ -246,7 +172,7 @@ class BilibiliSub(db.Model):
live_data = []
up_data = []
season_data = []
query = await cls.query.gino.all()
query = await cls.all()
for x in query:
if x.sub_type == "live":
live_data.append(x)
+38 -28
View File
@@ -1,28 +1,30 @@
from datetime import datetime
from typing import Any, Tuple
from nonebot import on_command, on_message, on_regex
from nonebot.adapters.onebot.v11 import (
Bot,
Event,
MessageEvent,
GroupMessageEvent,
Message,
Bot,
MessageEvent,
)
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor
from nonebot.params import CommandArg, RegexGroup
from nonebot.permission import SUPERUSER
from configs.config import NICKNAME, Config
from models.ban_user import BanUser
from services.log import logger
from utils.image_utils import BuildImage
from utils.manager import group_manager
from utils.utils import get_message_text, is_number
from nonebot.params import RegexGroup, CommandArg
from .utils import black_word_manager
from nonebot import on_command, on_message, on_regex
from configs.config import Config, NICKNAME
from nonebot.permission import SUPERUSER
from .data_source import show_black_text_image, set_user_punish
from services.log import logger
from models.ban_user import BanUser
from datetime import datetime
from utils.message_builder import image
from .model import BlackWord
from typing import Tuple, Any
from utils.utils import get_message_text, is_number
from .data_source import set_user_punish, show_black_text_image
from .model import BlackWord
from .utils import black_word_manager
__zx_plugin_name__ = "敏感词检测"
__plugin_usage__ = """
@@ -38,7 +40,7 @@ usage:
设置惩罚id需要通过 '记录名单u:xxxxxxxx' 获取
指令:
记录名单
设置惩罚 [user_id] [id] [punish_level]
设置惩罚 [user_id] [下标] [惩罚等级]
示例:记录名单
示例:记录名单u:12345678
示例:设置惩罚 12345678 1 4
@@ -150,24 +152,32 @@ async def _(
matcher: Matcher,
event: Event,
):
msg = get_message_text(event.json())
if (
isinstance(event, MessageEvent)
and event.is_tome()
and matcher.plugin_name == "black_word"
and not await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
and not get_message_text(event.json()).startswith("原神绑定")
and not msg.startswith("原神绑定")
):
# 屏蔽群权限-1的群
if isinstance(event, GroupMessageEvent) and group_manager.get_group_level(event.group_id) < 0:
return
user_id = event.user_id
group_id = event.group_id if isinstance(event, GroupMessageEvent) else None
msg = get_message_text(event.json())
if await black_word_manager.check(user_id, group_id, msg) and Config.get_config(
"black_word", "CONTAIN_BLACK_STOP_PROPAGATION"
# if str(event.user_id) not in bot.config.superusers:
# return logger.debug(f"超级用户跳过黑名单词汇检查 Message: {msg}", target=event.user_id)
if (
event.is_tome()
and matcher.plugin_name == "black_word"
and not await BanUser.is_ban(event.user_id)
):
matcher.stop_propagation()
# 屏蔽群权限-1的群
if (
isinstance(event, GroupMessageEvent)
and group_manager.get_group_level(event.group_id) < 0
):
return
user_id = event.user_id
group_id = event.group_id if isinstance(event, GroupMessageEvent) else None
msg = get_message_text(event.json())
if await black_word_manager.check(
user_id, group_id, msg
) and Config.get_config("black_word", "CONTAIN_BLACK_STOP_PROPAGATION"):
matcher.stop_propagation()
@show_black.handle()
+56 -62
View File
@@ -1,47 +1,34 @@
from services.db_context import db
from typing import Optional, List
from datetime import datetime, timedelta
from typing import List, Optional
from tortoise import fields
from services.db_context import Model
class BlackWord(db.Model):
__tablename__ = "black_word"
class BlackWord(Model):
# __tablename__ = "black_word"
id = db.Column(db.Integer(), primary_key=True, autoincrement=True)
user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
group_id = db.Column(db.BigInteger())
plant_text = db.Column(db.String())
black_word = db.Column(db.String())
punish = db.Column(db.String(), default="")
punish_level = db.Column(db.Integer())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField(null=True)
"""群聊id"""
plant_text = fields.TextField()
"""检测文本"""
black_word = fields.TextField()
"""黑名单词语"""
punish = fields.TextField(default="")
"""惩罚内容"""
punish_level = fields.IntField()
"""惩罚等级"""
create_time = fields.DatetimeField(auto_now_add=True)
"""创建时间"""
@classmethod
async def add_user_black_word(
cls,
user_qq: int,
group_id: Optional[int],
black_word: str,
plant_text: str,
punish_level: int,
):
"""
说明:
添加用户发送的敏感词
参数:
:param user_qq: 用户id
:param group_id: 群号
:param black_word: 黑名单词汇
:param plant_text: 消息文本
:param punish_level: 惩罚等级
"""
await cls.create(
user_qq=user_qq,
group_id=group_id,
plant_text=plant_text,
black_word=black_word,
punish_level=punish_level,
create_time=datetime.now(),
)
class Meta:
table = "black_word"
table_description = "惩罚机制数据表"
@classmethod
async def set_user_punish(
@@ -63,17 +50,21 @@ class BlackWord(db.Model):
user = None
if (not black_word and not id_) or not punish:
return False
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
if black_word:
user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first()
user = (
await cls.filter(user_qq=user_qq, black_word=black_word)
.order_by("id")
.first()
)
elif id_:
user_list = await query.gino.all()
user_list = await cls.filter(user_qq=user_qq).order_by("id").all()
if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)):
return False
user = user_list[id_]
if not user:
return False
await user.update(punish=cls.punish + punish + " ").apply()
user.punish = f"{user.punish}{punish} "
await user.save(update_fields=["punish"])
return True
@classmethod
@@ -88,15 +79,14 @@ class BlackWord(db.Model):
:param days: 周期天数
:param punish_level: 惩罚等级
"""
setattr(BlackWord, "count", db.func.count(cls.id).label("count"))
query = cls.select("count").where(
(cls.user_qq == user_qq)
& (cls.punish_level != -1)
& (cls.create_time > datetime.now() - timedelta(days=days))
query = cls.filter(
user_qq=user_qq,
create_time__gte=datetime.now() - timedelta(days=days),
punish_level__not_in=[-1],
)
if punish_level is not None:
query = query.where(cls.punish_level == punish_level)
return (await query.gino.first())[0]
query = query.filter(punish_level=punish_level)
return await query.count()
@classmethod
async def get_user_punish_level(cls, user_qq: int, days: int = 7) -> Optional[int]:
@@ -108,12 +98,14 @@ class BlackWord(db.Model):
:param days: 周期天数
"""
if (
query := await cls.query.where(cls.user_qq == user_qq)
.where(cls.create_time > datetime.now() - timedelta(days=days))
.order_by(cls.id.desc())
.gino.first()
user := await cls.filter(
user_qq=user_qq,
create_time__gte=datetime.now() - timedelta(days=days),
)
.order_by("id")
.first()
):
return query.punish_level
return user.punish_level
return None
@classmethod
@@ -133,16 +125,18 @@ class BlackWord(db.Model):
:param date: 日期
:param date_type: 日期查询类型
"""
query = cls.query
query = cls
if user_qq:
query = query.where(cls.user_qq == user_qq)
query = query.filter(user_qq=user_qq)
if group_id:
query = query.where(cls.group_id == group_id)
query = query.filter(group_id=group_id)
if date:
if date_type == "=":
query = query.where(cls.create_time == date)
query = query.filter(
create_time__range=[date, date + timedelta(days=1)]
)
elif date_type == ">":
query = query.where(cls.create_time > date)
query = query.filter(create_time__gte=date)
elif date_type == "<":
query = query.where(cls.create_time < date)
return await query.gino.all()
query = query.filter(create_time__lte=date)
return await query.order_by("id").all()
+37 -23
View File
@@ -1,15 +1,18 @@
from utils.utils import cn2py, get_bot
from configs.path_config import DATA_PATH
from typing import Optional, Union, Tuple
from .model import BlackWord
from configs.config import Config
from pathlib import Path
from services.log import logger
from models.ban_user import BanUser
from nonebot.adapters.onebot.v11 import ActionFailed
from models.group_member_info import GroupInfoUser
from utils.http_utils import AsyncHttpx
import random
from pathlib import Path
from typing import Optional, Tuple, Union
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import Config
from configs.path_config import DATA_PATH
from models.ban_user import BanUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.utils import cn2py, get_bot
from .model import BlackWord
try:
import ujson as json
@@ -49,7 +52,7 @@ class BlackWordManager:
"hanbi",
"hanpi",
"laji",
"fw"
"fw",
],
"5": [],
}
@@ -94,9 +97,9 @@ class BlackWordManager:
user_id, group_id, data[0], message, int(data[1])
)
return True
if Config.get_config(
"black_word", "ALAPI_CHECK_FLAG"
) and not await check_text(message):
if Config.get_config("black_word", "ALAPI_CHECK_FLAG") and not await check_text(
message
):
await send_msg(
0, None, f"USER {user_id} GROUP {group_id} ALAPI 疑似检测:{message}"
)
@@ -146,8 +149,12 @@ async def _add_user_black_word(
"black_word", "AUTO_ADD_PUNISH_LEVEL"
) and user_count > Config.get_config("black_word", "ADD_PUNISH_LEVEL_TO_COUNT"):
punish_level -= 1
await BlackWord.add_user_black_word(
user_id, group_id, black_word, message, punish_level
await BlackWord.create(
user_qq=user_id,
group_id=group_id,
plant_text=message,
black_word=black_word,
punish_level=punish_level,
)
logger.info(
f"已将 USER {user_id} GROUP {group_id} 添加至黑名单词汇记录 Black_word:{black_word} Plant_text:{message}"
@@ -172,7 +179,9 @@ async def _punish_handle(
# 用户周期内触发punish_level级惩罚的次数
user_count = await BlackWord.get_user_count(user_id, cycle_days, punish_level)
# 获取最近一次的惩罚等级,将在此基础上增加
punish_level = await BlackWord.get_user_punish_level(user_id, cycle_days) or punish_level
punish_level = (
await BlackWord.get_user_punish_level(user_id, cycle_days) or punish_level
)
# 容忍次数:List[int]
tolerate_count = Config.get_config("black_word", "TOLERATE_COUNT")
if not tolerate_count or len(tolerate_count) < 5:
@@ -226,15 +235,17 @@ async def _get_punish(
ban_4_duration = Config.get_config("black_word", "BAN_4_DURATION")
# 口头警告内容
warning_result = Config.get_config("black_word", "WARNING_RESULT")
try:
uname = (await GroupInfoUser.get_member_info(user_id, group_id)).user_name
except AttributeError:
if user := await GroupInfoUser.get_or_none(user_qq=user_id, group_id=group_id):
uname = user.user_name
else:
uname = user_id
# 永久ban
if id_ == 1:
if str(user_id) not in bot.config.superusers:
await BanUser.ban(user_id, 10, 99999999)
await send_msg(user_id, group_id, f"BlackWordChecker 永久ban USER {uname}({user_id})")
await send_msg(
user_id, group_id, f"BlackWordChecker 永久ban USER {uname}({user_id})"
)
logger.info(f"BlackWord 永久封禁 USER {user_id}...")
# 删除好友(有的话
elif id_ == 2:
@@ -319,4 +330,7 @@ async def check_text(text: str) -> bool:
return True
black_word_manager = BlackWordManager(DATA_PATH / "black_word" / "black_word.json", DATA_PATH / "black_word" / "black_py.json")
black_word_manager = BlackWordManager(
DATA_PATH / "black_word" / "black_word.json",
DATA_PATH / "black_word" / "black_py.json",
)
+3 -12
View File
@@ -1,13 +1,7 @@
from utils.http_utils import AsyncHttpx
from configs.config import Config
from bs4 import BeautifulSoup
import platform
# if platform.system() == "Windows":
# import asyncio
#
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from configs.config import Config
from utils.http_utils import AsyncHttpx
url = "http://www.eclzz.love"
@@ -28,10 +22,7 @@ async def get_bt_info(keyword: str, page: int):
for item in item_lst[:bt_max_num]:
divs = item.find_all("div")
title = (
str(divs[0].find("a").text)
.replace("<em>", "")
.replace("</em>", "")
.strip()
str(divs[0].find("a").text).replace("<em>", "").replace("</em>", "").strip()
)
spans = divs[2].find_all("span")
type_ = spans[0].text
+1 -1
View File
@@ -65,4 +65,4 @@ async def _():
mes = "[[_task|genshin_alc]]" + alc_img
for gid in gl:
if group_manager.check_group_task_status(gid, "genshin_alc"):
await bot.send_group_msg(group_id=int(gid), message="" + mes)
await bot.send_group_msg(group_id=int(gid), message=mes)
+13 -14
View File
@@ -1,18 +1,19 @@
from nonebot import on_command, Driver
from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent
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
import nonebot
from services.log import logger
from nonebot.permission import SUPERUSER
from typing import List
from datetime import datetime, timedelta
import os
import asyncio
import os
import time
from datetime import datetime, timedelta
from typing import List
import nonebot
from nonebot import Driver, on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageEvent
from nonebot.permission import SUPERUSER
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.browser import get_browser
from utils.image_utils import BuildImage
from utils.message_builder import image
__zx_plugin_name__ = "今日素材"
__plugin_usage__ = """
@@ -114,5 +115,3 @@ def get_background_height(weapons_img: List[str]) -> int:
last_weapon.save(weapons_img[-1])
return height
+56 -445
View File
@@ -1,219 +1,49 @@
from services.db_context import db
from typing import Optional, Union, List
from datetime import datetime, timedelta
import random
from datetime import datetime, timedelta
from typing import Optional
import pytz
from tortoise import fields
from tortoise.contrib.postgres.functions import Random
from services.db_context import Model
class Genshin(db.Model):
__tablename__ = "genshin"
class Genshin(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
uid = db.Column(db.BigInteger())
mys_id = db.Column(db.BigInteger())
cookie = db.Column(db.String(), default="")
today_query_uid = db.Column(db.String(), default="") # 该cookie今日查询的uid
auto_sign = db.Column(db.Boolean(), default=False)
auto_sign_time = db.Column(db.DateTime(timezone=True))
resin_remind = db.Column(db.Boolean(), default=False) # 树脂提醒
resin_recovery_time = db.Column(db.DateTime(timezone=True)) # 满树脂提醒日期
bind_group = db.Column(db.BigInteger())
login_ticket = db.Column(db.String(), default="")
stuid = db.Column(db.String(), default="")
stoken = db.Column(db.String(), default="")
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
uid = fields.BigIntField()
"""uid"""
mys_id: int = fields.BigIntField(null=True)
"""米游社id"""
cookie: str = fields.TextField(default="")
"""米游社cookie"""
auto_sign = fields.BooleanField(default=False)
"""是否自动签到"""
today_query_uid = fields.TextField(default="")
"""cookie今日查询uid"""
auto_sign_time = fields.DatetimeField(null=True)
"""签到日期时间"""
resin_remind = fields.BooleanField(default=False)
"""树脂提醒"""
resin_recovery_time = fields.DatetimeField(null=True)
"""满树脂提醒日期"""
bind_group: int = fields.BigIntField(null=True)
"""发送提示 绑定群聊"""
login_ticket = fields.TextField(default="")
"""login_ticket"""
stuid: str = fields.TextField(default="")
"""stuid"""
stoken: str = fields.TextField(default="")
"""stoken"""
_idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True)
@classmethod
async def add_uid(cls, user_qq: int, uid: int):
"""
说明:
添加一个uid
参数:
:param user_qq: 用户qq
:param uid: 原神uid
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.uid == uid))
user = await query.gino.first()
if not user:
await cls.create(
user_qq=user_qq,
uid=uid,
)
return True
return False
@classmethod
async def set_mys_id(cls, uid: int, mys_id: int) -> bool:
"""
说明:
设置米游社id
参数:
:param uid: 原神uid
:param mys_id: 米游社id
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(mys_id=mys_id).apply()
return True
return False
@classmethod
async def set_bind_group(cls, uid: int, bind_group) -> bool:
"""
说明:
绑定group_id,除私聊外的提醒将在此群发送
参数:
:param uid: uid
:param bind_group: 群号
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(bind_group=bind_group).apply()
return True
return False
@classmethod
async def get_bind_group(cls, uid: int) -> Optional[int]:
"""
说明:
获取用户绑定的群聊
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
if user:
return user.bind_group
return None
@classmethod
async def set_cookie(cls, uid: int, cookie: str) -> bool:
"""
说明:
设置cookie
参数:
:param uid: 原神uid
:param cookie: 米游社id
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(cookie=cookie).apply()
return True
return False
@classmethod
async def set_resin_remind(cls, uid: int, flag: bool) -> bool:
"""
说明:
设置体力提醒
参数:
:param uid: 原神uid
:param flag: 开关状态
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(resin_remind=flag).apply()
return True
return False
@classmethod
async def set_user_resin_recovery_time(cls, uid: int, date: datetime):
"""
说明:
设置体力完成时间
参数:
:param uid: uid
:param date: 提醒日期
"""
u = await cls.query.where(cls.uid == uid).gino.first()
if u:
await u.update(resin_recovery_time=date).apply()
@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()
if u:
return u.resin_recovery_time.astimezone(pytz.timezone("Asia/Shanghai"))
return None
@classmethod
async def get_all_resin_remind_user(cls) -> List["Genshin"]:
"""
说明:
获取所有开启体力提醒的用户
"""
return await cls.query.where(cls.resin_remind == True).gino.all()
@classmethod
async def clear_resin_remind_time(cls, uid: int) -> bool:
"""
说明:
清空提醒日期
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
if user:
await user.update(resin_recovery_time=None).apply()
return True
return False
@classmethod
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
"""
说明:
设置米游社/原神自动签到
参数:
:param uid: 原神uid
:param flag: 开关状态
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(auto_sign=flag).apply()
return True
return False
@classmethod
async def get_all_auto_sign_user(cls) -> List["Genshin"]:
"""
说明:
获取所有开启自动签到的用户
"""
return await cls.query.where(cls.auto_sign == True).gino.all()
@classmethod
async def get_all_sign_user(cls) -> List["Genshin"]:
"""
说明:
获取 原神 所有今日签到用户
"""
return await cls.query.where(cls.auto_sign_time != None).gino.all()
@classmethod
async def clear_sign_time(cls, uid: int) -> bool:
"""
说明:
清空签到日期
参数:
:param uid: uid
"""
user = await cls.query.where(cls.uid == uid).gino.first()
if user:
await user.update(auto_sign_time=None).apply()
return True
return False
class Meta:
table = "genshin"
table_description = "原神数据表"
unique_together = ("user_qq", "uid")
@classmethod
async def random_sign_time(cls, uid: int) -> Optional[datetime]:
@@ -223,262 +53,43 @@ class Genshin(db.Model):
说明:
:param uid: uid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
user = await cls.get_or_none(uid=uid)
if user and user.cookie:
if user.auto_sign_time and user.auto_sign_time.astimezone(
pytz.timezone("Asia/Shanghai")
pytz.timezone("Asia/Shanghai")
) - timedelta(seconds=2) >= datetime.now(pytz.timezone("Asia/Shanghai")):
return user.auto_sign_time.astimezone(pytz.timezone("Asia/Shanghai"))
hours = int(str(datetime.now()).split()[1].split(":")[0])
minutes = int(str(datetime.now()).split()[1].split(":")[1])
date = (
datetime.now()
+ timedelta(days=1)
- timedelta(hours=hours)
- timedelta(minutes=minutes - 1)
datetime.now()
+ timedelta(days=1)
- timedelta(hours=hours)
- timedelta(minutes=minutes - 1)
)
random_hours = random.randint(0, 22)
random_minutes = random.randint(1, 59)
date += timedelta(hours=random_hours) + timedelta(minutes=random_minutes)
await user.update(auto_sign_time=date).apply()
user.auto_sign_time = date
await user.save(update_fields=["auto_sign_time"])
return date
return None
@classmethod
async def get_query_cookie(cls, uid: int) -> Optional[str]:
async def random_cookie(cls, uid: int) -> Optional[str]:
"""
说明:
获取查询角色信息cookie
随机获取查询角色信息cookie
参数:
:param uid: 原神uid
"""
# 查找用户今日是否已经查找过,防止重复
query = cls.query.where(cls.today_query_uid.contains(str(uid)))
x = await query.gino.first()
if x:
await cls._add_query_uid(uid, uid)
return x.cookie
for u in await cls.query.where(cls.cookie != "").order_by(db.func.random()).gino.all():
if not u.today_query_uid or len(u.today_query_uid[:-1].split()) < 30:
await cls._add_query_uid(uid, u.uid)
return u.cookie
return None
@classmethod
async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]:
"""
说明:
获取用户cookie
参数:
:param uid:原神uid
:param flag:必须使用自己的cookie
"""
cookie = await cls._get_user_data(None, uid, "cookie")
if not cookie and not flag:
cookie = await cls.get_query_cookie(uid)
return cookie
@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()
@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()
@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")
@classmethod
async def get_user_mys_id(cls, uid: int) -> Optional[int]:
"""
说嘛:
获取用户米游社id
参数:
:param uid:原神id
"""
return await cls._get_user_data(None, uid, "mys_id")
@classmethod
async def delete_user_cookie(cls, uid: int):
"""
说明:
删除用户cookie
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
user = await cls.get_or_none(today_query_uid__contains=str(uid))
if user:
await user.update(cookie="").apply()
@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()
user = await query.gino.first()
if not user:
return False
await user.delete()
return True
@classmethod
async def _add_query_uid(cls, uid: int, cookie_uid: int):
"""
说明:
添加每日查询重复uid的cookie
参数:
:param uid: 原神uid
:param cookie_uid: cookie的uid
"""
query = cls.query.where(cls.uid == cookie_uid).with_for_update()
user = await query.gino.first()
await user.update(today_query_uid=user.today_query_uid + f"{uid} ").apply()
@classmethod
async def _get_user_data(
cls, user_qq: Optional[int], uid: Optional[int], type_: str
) -> Optional[Union[int, str]]:
"""
说明:
获取用户数据
参数:
:param user_qq: 用户qq
:param uid: uid
:param type_: 数据类型
"""
if type_ == "uid":
user = await cls.query.where(cls.user_qq == user_qq).gino.first()
return user.uid if user else None
user = await cls.query.where(cls.uid == uid).gino.first()
if not user:
return None
if type_ == "mys_id":
return user.mys_id
elif type_ == "cookie":
return user.cookie
return None
@classmethod
async def reset_today_query_uid(cls):
for u in await cls.query.with_for_update().gino.all():
if u.today_query_uid:
await u.update(today_query_uid="").apply()
@classmethod
async def set_stuid(cls, uid: int, stuid: str) -> bool:
"""
说明:
设置stuid
参数:
:param uid: 原神uid
:param stuid: stuid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(stuid=stuid).apply()
return True
return False
@classmethod
async def set_stoken(cls, uid: int, stoken: str) -> bool:
"""
说明:
设置stoken
参数:
:param uid: 原神uid
:param stoken: stoken
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(stoken=stoken).apply()
return True
return False
@classmethod
async def set_login_ticket(cls, uid: int, login_ticket: str) -> bool:
"""
说明:
设置login_ticket
参数:
:param uid: 原神uid
:param login_ticket: login_ticket
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(login_ticket=login_ticket).apply()
return True
return False
# 获取login_ticket
@classmethod
async def get_login_ticket(cls, uid: int) -> Optional[str]:
"""
说明:
获取login_ticket
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.login_ticket
return None
# 获取stuid
@classmethod
async def get_stuid(cls, uid: int) -> Optional[str]:
"""
说明:
获取stuid
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.stuid
return None
# 获取stoken
@classmethod
async def get_stoken(cls, uid: int) -> Optional[str]:
"""
说明:
获取stoken
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.stoken
for user in await cls.filter(cookie__not="").annotate(rand=Random()).all():
if not user.today_query_uid or len(user.today_query_uid[:-1].split()) < 30:
user.today_query_uid = user.today_query_uid + f"{uid} "
await user.save(update_fields=["today_query_uid"])
return user.cookie
return None
@@ -1,9 +1,10 @@
from configs.config import Config
import json
import time
import random
import hashlib
import json
import random
import string
import time
from configs.config import Config
def _md5(text):
@@ -15,7 +16,7 @@ def _md5(text):
def get_old_ds() -> str:
n = Config.get_config("genshin", "n")
i = str(int(time.time()))
r = ''.join(random.sample(string.ascii_lowercase + string.digits, 6))
r = "".join(random.sample(string.ascii_lowercase + string.digits, 6))
c = _md5("salt=" + n + "&t=" + i + "&r=" + r)
return i + "," + r + "," + c
@@ -33,7 +34,7 @@ def get_ds(q: str = "", b: dict = None) -> str:
def random_hex(length: int) -> str:
result = hex(random.randint(0, 16 ** length)).replace("0x", "").upper()
result = hex(random.randint(0, 16**length)).replace("0x", "").upper()
if len(result) < length:
result = "0" * (length - len(result)) + result
return result
+61 -48
View File
@@ -1,13 +1,16 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
from utils.utils import is_number
from .._models import Genshin
from services.log import logger
from nonebot.params import CommandArg, Command
from typing import Tuple
from utils.http_utils import AsyncHttpx
import json
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageEvent
from nonebot.params import Command, CommandArg
from services.log import logger
from utils.depends import OneCommand
from utils.http_utils import AsyncHttpx
from utils.utils import is_number
from .._models import Genshin
__zx_plugin_name__ = "原神绑定"
__plugin_usage__ = """
@@ -43,82 +46,94 @@ unbind = on_command("原神解绑", priority=5, block=True)
web_Api = "https://api-takumi.mihoyo.com"
bbs_Cookie_url = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}"
bbs_Cookie_url2 = web_Api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
bbs_Cookie_url2 = (
web_Api
+ "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
)
@bind.handle()
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
cmd = cmd[0]
async def _(event: MessageEvent, cmd: str = OneCommand(), arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
user = await Genshin.get_or_none(user_qq=event.user_id)
if cmd in ["原神绑定uid", "原神绑定米游社id"]:
if not is_number(msg):
await bind.finish("uid/id必须为纯数字!", at_senders=True)
msg = int(msg)
if cmd == "原神绑定uid":
uid = await Genshin.get_user_uid(event.user_id)
if uid:
await bind.finish(f"您已绑定过uid:{uid},如果希望更换uid,请先发送原神解绑")
flag = await Genshin.add_uid(event.user_id, msg)
if not flag:
if user:
await bind.finish(f"您已绑定过uid:{user.uid},如果希望更换uid,请先发送原神解绑")
if await Genshin.get_or_none(user_qq=event.user_id, uid=msg):
await bind.finish("添加失败,该uid可能已存在...")
user = await Genshin.create(user_qq=event.user_id, uid=msg)
_x = f"已成功添加原神uid:{msg}"
elif cmd == "原神绑定米游社id":
uid = await Genshin.get_user_uid(event.user_id)
if not uid:
if not user:
await bind.finish("请先绑定原神uid..")
await Genshin.set_mys_id(uid, msg)
_x = f"已成功为uid:{uid} 设置米游社id:{msg}"
user.mys_id = int(msg)
_x = f"已成功为uid:{user.uid} 设置米游社id:{msg}"
else:
if not msg:
await bind.finish("""私聊发送!!
await bind.finish(
"""私聊发送!!
1.以无痕模式打开浏览器(Edge请新建InPrivate窗口)
2.打开http://bbs.mihoyo.com/ys/并登陆
2.打开http://bbs.mihoyo.com/ys/ 并登陆
3.登陆后打开http://user.mihoyo.com/进行登陆
4.按下F12,打开控制台,输入以下命令:
var cookie=document.cookie;var ask=confirm('Cookie:'+cookie+'\\n\\nDo you want to copy the cookie to the clipboard?');if(ask==true){copy(cookie);msg=cookie}else{msg='Cancel'}
5.私聊发送:原神绑定cookie 刚刚复制的cookie""")
5.私聊发送:原神绑定cookie 刚刚复制的cookie"""
)
if isinstance(event, GroupMessageEvent):
await bind.finish("请立即撤回你的消息并私聊发送!")
uid = await Genshin.get_user_uid(event.user_id)
if not uid:
if not user:
await bind.finish("请先绑定原神uid..")
if msg.startswith('"') or msg.startswith("'"):
msg = msg[1:]
if msg.endswith('"') or msg.endswith("'"):
msg = msg[:-1]
await Genshin.set_cookie(uid, msg)
cookie = msg
# 用: 代替=, ,代替;
cookie = '{"' + cookie.replace('=', '": "').replace("; ", '","') + '"}'
print(cookie)
cookie = '{"' + cookie.replace("=", '": "').replace("; ", '","') + '"}'
# print(cookie)
cookie_json = json.loads(cookie)
print(cookie_json)
if 'login_ticket' not in cookie_json:
# print(cookie_json)
if "login_ticket" not in cookie_json:
await bind.finish("请发送正确完整的cookie!")
login_ticket = cookie_json['login_ticket']
user.cookie = str(msg)
login_ticket = cookie_json["login_ticket"]
# try:
res = await AsyncHttpx.get(url=bbs_Cookie_url.format(login_ticket))
res.encoding = "utf-8"
data = json.loads(res.text)
print(data)
# print(data)
if "成功" in data["data"]["msg"]:
stuid = str(data["data"]["cookie_info"]["account_id"])
res = await AsyncHttpx.get(url=bbs_Cookie_url2.format(
login_ticket, stuid))
res = await AsyncHttpx.get(url=bbs_Cookie_url2.format(login_ticket, stuid))
res.encoding = "utf-8"
data = json.loads(res.text)
stoken = data["data"]["list"][0]["token"]
# await Genshin.set_cookie(uid, cookie)
await Genshin.set_stoken(uid, stoken)
await Genshin.set_stuid(uid, stuid)
await Genshin.set_login_ticket(uid, login_ticket)
user.stoken = stoken
user.stuid = stuid
user.login_ticket = login_ticket
# except Exception as e:
# await bind.finish("获取登陆信息失败,请检查cookie是否正确或更新cookie")
elif data["data"]["msg"] == "登录信息已失效,请重新登录":
await bind.finish("登录信息失效,请重新获取最新cookie进行绑定")
_x = f"已成功为uid:{uid} 设置cookie"
_x = f"已成功为uid:{user.uid} 设置cookie"
if isinstance(event, GroupMessageEvent):
await Genshin.set_bind_group(uid, event.group_id)
user.bind_group = event.group_id
if user:
await user.save(
update_fields=[
"mys_id",
"cookie",
"stoken",
"stuid",
"login_ticket",
"bind_group",
]
)
await bind.send(_x)
logger.info(
f"(USER {event.user_id}, "
@@ -129,12 +144,10 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message
@unbind.handle()
async def _(event: MessageEvent):
if await Genshin.delete_user(event.user_id):
await unbind.send("用户数据删除成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f"原神解绑"
)
else:
await unbind.send("该用户数据不存在..")
await Genshin.filter(user_qq=event.user_id).delete()
await unbind.send("用户数据删除成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f"原神解绑"
)
@@ -1,14 +1,17 @@
from .data_source import get_sign_reward_list, genshin_sign
from ..mihoyobbs_sign import mihoyobbs_sign
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from nonebot import on_command
from services.log import logger
from .init_task import add_job, scheduler, _sign
from apscheduler.jobstores.base import JobLookupError
from .._models import Genshin
from nonebot.params import Command
from typing import Tuple
from apscheduler.jobstores.base import JobLookupError
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from nonebot.params import Command
from services.log import logger
from utils.depends import OneCommand
from .._models import Genshin
from ..mihoyobbs_sign import mihoyobbs_sign
from .data_source import genshin_sign, get_sign_reward_list
from .init_task import _sign, add_job, scheduler
__zx_plugin_name__ = "原神自动签到"
__plugin_usage__ = """
@@ -39,45 +42,46 @@ genshin_matcher = on_command(
@genshin_matcher.handle()
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
cmd = cmd[0]
uid = await Genshin.get_user_uid(event.user_id)
async def _(event: MessageEvent, cmd: str = OneCommand()):
user = await Genshin.get_or_none(user_qq=event.user_id)
if not user:
await genshin_matcher.finish("请先绑定user.uid...")
if cmd == "查看我的cookie":
my_cookie = await Genshin.get_user_cookie(uid, True)
if isinstance(event, GroupMessageEvent):
await genshin_matcher.finish("请私聊查看您的cookie!")
await genshin_matcher.finish("您的cookie为" + my_cookie)
if not uid or not await Genshin.get_user_cookie(uid, True):
await genshin_matcher.finish("请先绑定uid和cookie!")
# if "account_id" not in await Genshin.get_user_cookie(uid, True):
await genshin_matcher.finish("您的cookie为" + user.cookie)
if not user.uid or not user.cookie:
await genshin_matcher.finish("请先绑定user.uid和cookie!")
# if "account_id" not in await Genshin.get_user_cookie(user.uid, True):
# await genshin_matcher.finish("请更新cookie!")
if cmd == "原神我硬签":
try:
await genshin_matcher.send("正在进行签到...", at_sender=True)
msg = await genshin_sign(uid)
msg = await genshin_sign(user.uid)
return_data = await mihoyobbs_sign(event.user_id)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{uid} 原神签到"
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{user.uid} 原神签到"
)
logger.info(msg)
# 硬签,移除定时任务
try:
for i in range(3):
scheduler.remove_job(f"genshin_auto_sign_{uid}_{event.user_id}_{i}",)
scheduler.remove_job(
f"genshin_auto_sign_{user.uid}_{event.user_id}_{i}",
)
except JobLookupError:
pass
u = await Genshin.get_user_by_uid(uid)
if u and u.auto_sign:
await u.clear_sign_time(uid)
next_date = await Genshin.random_sign_time(uid)
add_job(event.user_id, uid, next_date)
if user.auto_sign:
user.auto_sign_time = None
next_date = await Genshin.random_sign_time(user.uid)
add_job(event.user_id, user.uid, next_date)
msg += f"\n{return_data}\n因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
except Exception as e:
msg = "原神签到失败..请尝试检查cookie或报告至管理员!"
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{uid} 原神签到发生错误 "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{user.uid} 原神签到发生错误 "
f"{type(e)}:{e}"
)
msg = msg or "请检查cookie是否更新!"
@@ -85,13 +89,16 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
else:
for i in range(3):
try:
scheduler.remove_job(f"genshin_auto_sign_{uid}_{event.user_id}_{i}")
scheduler.remove_job(
f"genshin_auto_sign_{user.uid}_{event.user_id}_{i}"
)
except JobLookupError:
pass
if cmd[0] == "开":
await Genshin.set_auto_sign(uid, True)
next_date = await Genshin.random_sign_time(uid)
add_job(event.user_id, uid, next_date)
next_date = await Genshin.random_sign_time(user.uid)
user.auto_sign = True
user.auto_sign_time = next_date
add_job(event.user_id, user.uid, next_date)
await genshin_matcher.send(
f"已开启原神自动签到!\n下一次签到时间为:{next_date.replace(microsecond=0)}",
at_sender=True,
@@ -102,11 +109,13 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
f" 开启原神自动签到"
)
else:
await Genshin.set_auto_sign(uid, False)
await Genshin.clear_sign_time(uid)
user.auto_sign = False
user.auto_sign_time = None
await genshin_matcher.send(f"已关闭原神自动签到!", at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 关闭原神自动签到"
)
if user:
await user.save(update_fields=["auto_sign_time", "auto_sign"])
@@ -1,14 +1,16 @@
from utils.http_utils import AsyncHttpx
from configs.config import Config
from services.log import logger
from ..mihoyobbs_sign.setting import *
from .._models import Genshin
from typing import Optional, Dict
import hashlib
import random
import string
import uuid
import time
import uuid
from typing import Dict, Optional
from configs.config import Config
from services.log import logger
from utils.http_utils import AsyncHttpx
from .._models import Genshin
from ..mihoyobbs_sign.setting import *
async def genshin_sign(uid: int) -> Optional[str]:
@@ -28,10 +30,10 @@ async def genshin_sign(uid: int) -> Optional[str]:
sign_list = await get_sign_reward_list()
get_reward = sign_list["data"]["awards"][
int(sign_info["total_sign_day"]) - 1
]["name"]
]["name"]
reward_num = sign_list["data"]["awards"][
int(sign_info["total_sign_day"]) - 1
]["cnt"]
]["cnt"]
get_im = f"本次签到获得:{get_reward}x{reward_num}"
logger.info("get_im:" + get_im + "\nsign_info:" + str(sign_info))
if status == "OK" and sign_info["is_sign"]:
@@ -64,7 +66,7 @@ def timestamp() -> int:
def random_text(num: int) -> str:
return ''.join(random.sample(string.ascii_lowercase + string.digits, num))
return "".join(random.sample(string.ascii_lowercase + string.digits, num))
def md5(text: str) -> str:
@@ -75,8 +77,7 @@ def md5(text: str) -> str:
# 生成一个device id
def get_device_id(cookie) -> str:
return str(uuid.uuid3(uuid.NAMESPACE_URL, cookie)).replace(
'-', '').upper()
return str(uuid.uuid3(uuid.NAMESPACE_URL, cookie)).replace("-", "").upper()
async def _sign(uid: int, server_id: str = "cn_gf01") -> Optional[Dict[str, str]]:
@@ -88,18 +89,20 @@ async def _sign(uid: int, server_id: str = "cn_gf01") -> Optional[Dict[str, str]
if str(uid)[0] == "5":
server_id = "cn_qd01"
try:
cookie = await Genshin.get_user_cookie(uid, True)
headers['DS'] = get_ds(web=True)
headers['Referer'] = 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true' \
f'&act_id={genshin_Act_id}&utm_source=bbs&utm_medium=mys&utm_campaign=icon'
headers['Cookie'] = cookie
headers['x-rpc-device_id'] = get_device_id(cookie)
req = await AsyncHttpx.post(
url=genshin_Signurl,
headers=headers,
json={"act_id": genshin_Act_id, "uid": uid, "region": server_id},
)
return req.json()
if user := await Genshin.get_or_none(uid=uid):
headers["DS"] = get_ds(web=True)
headers["Referer"] = (
"https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true"
f"&act_id={genshin_Act_id}&utm_source=bbs&utm_medium=mys&utm_campaign=icon"
)
headers["Cookie"] = user.cookie
headers["x-rpc-device_id"] = get_device_id(user.cookie)
req = await AsyncHttpx.post(
url=genshin_Signurl,
headers=headers,
json={"act_id": genshin_Act_id, "uid": uid, "region": server_id},
)
return req.json()
except Exception as e:
logger.error(f"米游社签到发生错误 UID:{uid} {type(e)}:{e}")
return None
@@ -129,17 +132,22 @@ async def _get_sign_info(uid: int, server_id: str = "cn_gf01"):
if str(uid)[0] == "5":
server_id = "cn_qd01"
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/event/bbs_sign_reward/info?act_id=e202009291139501&region={server_id}&uid={uid}",
headers={
"x-rpc-app_version": str(Config.get_config("genshin", "mhyVersion")),
"Cookie": await Genshin.get_user_cookie(int(uid), True),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": str(Config.get_config("genshin", "client_type")),
"Referer": "https://webstatic.mihoyo.com/",
},
)
return req.json()
if user := await Genshin.get_or_none(uid=uid):
req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/event/bbs_sign_reward/info?act_id=e202009291139501&region={server_id}&uid={uid}",
headers={
"x-rpc-app_version": str(
Config.get_config("genshin", "mhyVersion")
),
"Cookie": user.cookie,
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": str(
Config.get_config("genshin", "client_type")
),
"Referer": "https://webstatic.mihoyo.com/",
},
)
return req.json()
except Exception as e:
logger.error(f"获取签到信息发生错误 UID:{uid} {type(e)}:{e}")
return None
@@ -1,17 +1,19 @@
from .data_source import genshin_sign
from ..mihoyobbs_sign import mihoyobbs_sign
from models.group_member_info import GroupInfoUser
from utils.message_builder import at
from services.log import logger
from utils.utils import scheduler, get_bot
from apscheduler.jobstores.base import ConflictingIdError
from .._models import Genshin
from datetime import datetime, timedelta
from nonebot import Driver
import nonebot
import random
import pytz
from datetime import datetime, timedelta
import nonebot
import pytz
from apscheduler.jobstores.base import ConflictingIdError
from nonebot import Driver
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.message_builder import at
from utils.utils import get_bot, scheduler
from .._models import Genshin
from ..mihoyobbs_sign import mihoyobbs_sign
from .data_source import genshin_sign
driver: Driver = nonebot.get_driver()
@@ -21,7 +23,7 @@ async def _():
"""
启动时分配定时任务
"""
g_list = await Genshin.get_all_auto_sign_user()
g_list = await Genshin.filter(auto_sign=True).all()
for u in g_list:
if u.auto_sign_time:
if date := await Genshin.random_sign_time(u.uid):
@@ -33,7 +35,8 @@ async def _():
args=[u.user_qq, u.uid, 0],
)
logger.info(
f"genshin_sign add_job:USER:{u.user_qq} UID:{u.uid} " f"{date} 原神自动签到"
f"genshin_sign add_job:USER:{u.user_qq} UID:{u.uid} "
f"{date} 原神自动签到"
)
@@ -110,10 +113,12 @@ async def _sign(user_id: int, uid: int, count: int):
await bot.send_private_msg(user_id=user_id, message=return_data)
await bot.send_private_msg(user_id=user_id, message=msg)
else:
if not (group_id := await Genshin.get_bind_group(uid)):
group_list = await GroupInfoUser.get_user_all_group(user_id)
if group_list:
group_id = group_list[0]
await bot.send_group_msg(
group_id=group_id, message=at(user_id) + msg
)
if user := await Genshin.get_or_none(uid=uid):
group_id = user.bind_group
if not group_id:
if group_list := await GroupInfoUser.get_user_all_group(user_id):
group_id = group_list[0]
if group_id:
await bot.send_group_msg(
group_id=group_id, message=at(user_id) + msg
)
@@ -1,14 +1,16 @@
from nonebot.adapters.onebot.v11 import MessageEvent
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot.params import Command
from services.log import logger
# from .init_task import add_job, scheduler, _sign
# from apscheduler.jobstores.base import JobLookupError
from .._models import Genshin
from nonebot.params import Command
from typing import Tuple
from .mihoyobbs import *
__zx_plugin_name__ = "米游社自动签到"
__plugin_usage__ = """
usage:
@@ -28,12 +30,10 @@ __plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["原神签到"],
"cmd": ["米游社签到"],
}
mihoyobbs_matcher = on_command(
"米游社签到", aliases={"米游社我硬签"}, priority=5, block=True
)
mihoyobbs_matcher = on_command("米游社签到", aliases={"米游社我硬签"}, priority=5, block=True)
@mihoyobbs_matcher.handle()
@@ -47,24 +47,29 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
async def mihoyobbs_sign(user_id):
uid = await Genshin.get_user_uid(user_id)
if not uid or not await Genshin.get_user_cookie(uid, True):
user = await Genshin.get_or_none(user_qq=user_id)
if not user or not user.uid or not user.cookie:
await mihoyobbs_matcher.finish("请先绑定uid和cookie!", at_sender=True)
stuid = await Genshin.get_stuid(uid)
stoken = await Genshin.get_stoken(uid)
cookie = await Genshin.get_user_cookie(uid)
bbs = mihoyobbs.Mihoyobbs(stuid=stuid, stoken=stoken, cookie=cookie)
bbs = mihoyobbs.Mihoyobbs(stuid=user.stuid, stoken=user.stoken, cookie=user.cookie)
await bbs.init()
return_data = ""
if bbs.Task_do["bbs_Sign"] and bbs.Task_do["bbs_Read_posts"] and bbs.Task_do["bbs_Like_posts"] and \
bbs.Task_do["bbs_Share"]:
return_data += f"今天的米游社签到任务已经全部完成了!\n" \
f"一共获得{mihoyobbs.today_have_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
logger.info(f"今天已经全部完成了!一共获得{mihoyobbs.today_have_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币")
if (
bbs.Task_do["bbs_Sign"]
and bbs.Task_do["bbs_Read_posts"]
and bbs.Task_do["bbs_Like_posts"]
and bbs.Task_do["bbs_Share"]
):
return_data += (
f"今天的米游社签到任务已经全部完成了!\n"
f"一共获得{mihoyobbs.today_have_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
)
logger.info(
f"今天已经全部完成了!一共获得{mihoyobbs.today_have_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币"
)
else:
i = 0
print("开始签到")
print(mihoyobbs.today_have_get_coins)
# print("开始签到")
# print(mihoyobbs.today_have_get_coins)
while mihoyobbs.today_get_coins != 0 and i < 3:
# if i > 0:
await bbs.refresh_list()
@@ -74,8 +79,12 @@ async def mihoyobbs_sign(user_id):
await bbs.share_post()
await bbs.get_tasks_list()
i += 1
return_data += "\n" + f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币\n" \
f"还能获得{mihoyobbs.today_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
logger.info(f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币,"
f"还能获得{mihoyobbs.today_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币")
return_data += (
"\n" + f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币\n"
f"还能获得{mihoyobbs.today_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
)
logger.info(
f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币,"
f"还能获得{mihoyobbs.today_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币"
)
return return_data
@@ -1,9 +1,10 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from services.log import logger
from .data_source import get_user_memo, get_memo
from .._models import Genshin
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from services.log import logger
from .._models import Genshin
from .data_source import get_memo, get_user_memo
__zx_plugin_name__ = "原神便笺查询"
__plugin_usage__ = """
@@ -27,30 +28,27 @@ __plugin_settings__ = {
__plugin_block_limit__ = {}
query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True)
query_memo_matcher = on_command(
"原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True
)
@query_memo_matcher.handle()
async def _(event: MessageEvent):
uid = await Genshin.get_user_uid(event.user_id)
if not uid or not await Genshin.get_user_cookie(uid, True):
user = await Genshin.get_or_none(user_qq=event.user_id)
if not user or not user.uid or not user.cookie:
await query_memo_matcher.finish("请先绑定uid和cookie!")
if isinstance(event, GroupMessageEvent):
uname = event.sender.card or event.sender.nickname
else:
uname = event.sender.nickname
data = await get_user_memo(event.user_id, uid, uname)
data = await get_user_memo(event.user_id, user.uid, uname)
if data:
await query_memo_matcher.send(data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
f"使用原神便笺查询 uid:{uid}"
f"使用原神便笺查询 uid:{user.uid}"
)
else:
await query_memo_matcher.send("未查询到数据...")
@@ -1,20 +1,22 @@
from typing import Optional, Union
from nonebot.adapters.onebot.v11 import MessageSegment
from configs.config import Config
from asyncio.exceptions import TimeoutError
from services.log import logger
from configs.path_config import IMAGE_PATH
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
from utils.utils import get_user_avatar
from utils.message_builder import image
from .._utils import get_ds
from .._models import Genshin
from io import BytesIO
from nonebot import Driver
import asyncio
import nonebot
from asyncio.exceptions import TimeoutError
from io import BytesIO
from typing import Optional, Tuple, Union
import nonebot
from nonebot import Driver
from nonebot.adapters.onebot.v11 import MessageSegment
from configs.config import Config
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from utils.message_builder import image
from utils.utils import get_user_avatar
from .._models import Genshin
from .._utils import get_ds
driver: Driver = nonebot.get_driver()
@@ -26,10 +28,7 @@ memo_path.mkdir(exist_ok=True, parents=True)
@driver.on_startup
async def _():
for name, url in zip(
[
"resin.png", "task.png", "resin_discount.png", "chengehu.png",
"zhibian.png"
],
["resin.png", "task.png", "resin_discount.png", "chengehu.png", "zhibian.png"],
[
"https://upload-bbs.mihoyo.com/upload/2021/09/29/8819732/54266243c7d15ba31690c8f5d63cc3c6_71491376413333325"
"20.png?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,png",
@@ -45,8 +44,9 @@ async def _():
logger.info(f"已下载原神便签资源 -> {file}...")
async def get_user_memo(user_id: int, uid: int,
uname: str) -> Optional[Union[str, MessageSegment]]:
async def get_user_memo(
user_id: int, uid: int, uname: str
) -> Optional[Union[str, MessageSegment]]:
uid = str(uid)
if uid[0] in ["1", "2"]:
server_id = "cn_gf01"
@@ -57,21 +57,17 @@ async def get_user_memo(user_id: int, uid: int,
return await parse_data_and_draw(user_id, uid, server_id, uname)
async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
async def get_memo(uid: str, server_id: str) -> Tuple[Union[str, dict], int]:
try:
req = await AsyncHttpx.get(
url=
f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
headers={
"DS": get_ds(f"role_id={uid}&server={server_id}"),
"x-rpc-app_version": Config.get_config("genshin",
"mhyVersion"),
"User-Agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": Config.get_config("genshin",
"client_type"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.get_user_cookie(int(uid))
"Cookie": await Genshin.random_cookie(uid),
},
)
data = req.json()
@@ -85,18 +81,13 @@ async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
return "发生了一些错误,请稍后再试", 998
def create_border(image_name: str, content: str, notice_text: str,
value: str) -> BuildImage:
border = BuildImage(500,
75,
color="#E0D9D1",
font="HYWenHei-85W.ttf",
font_size=20)
text_bk = BuildImage(350,
75,
color="#F5F1EB",
font_size=23,
font="HYWenHei-85W.ttf")
def create_border(
image_name: str, content: str, notice_text: str, value: str
) -> BuildImage:
border = BuildImage(500, 75, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20)
text_bk = BuildImage(
350, 75, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf"
)
_x = 70 if image_name == "resin.png" else 50
_px = 10 if image_name == "resin.png" else 20
text_bk.paste(
@@ -119,15 +110,14 @@ def create_border(image_name: str, content: str, notice_text: str,
True,
)
font_width, _ = border.getsize(value)
border.text((350 + 76 - int(font_width / 2), 0),
value,
center_type="by_height")
border.text((350 + 76 - int(font_width / 2), 0), value, center_type="by_height")
border.paste(text_bk, (2, 0), center_type="by_height")
return border
async def parse_data_and_draw(user_id: int, uid: str, server_id: str,
uname: str) -> Union[str, MessageSegment]:
async def parse_data_and_draw(
user_id: int, uid: str, server_id: str, uname: str
) -> Union[str, MessageSegment]:
data, code = await get_memo(uid, server_id)
if code != 200:
return data
@@ -138,11 +128,13 @@ async def parse_data_and_draw(user_id: int, uid: str, server_id: str,
if not role_avatar.exists():
await AsyncHttpx.download_file(x["avatar_side_icon"], role_avatar)
return await asyncio.get_event_loop().run_in_executor(
None, _parse_data_and_draw, data, user_avatar, uid, uname)
None, _parse_data_and_draw, data, user_avatar, uid, uname
)
def _parse_data_and_draw(data: dict, user_avatar: BytesIO, uid: int,
uname: str) -> Union[str, MessageSegment]:
def _parse_data_and_draw(
data: dict, user_avatar: BytesIO, uid: int, uname: str
) -> Union[str, MessageSegment]:
current_resin = data["current_resin"] # 当前树脂
max_resin = data["max_resin"] # 最大树脂
resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
@@ -157,33 +149,24 @@ def _parse_data_and_draw(data: dict, user_avatar: BytesIO, uid: int,
max_coin = data["max_home_coin"] # 最大宝钱
coin_recovery_time = data["home_coin_recovery_time"] # 宝钱全部回复时间
transformer_available = data["transformer"]["obtained"] # 参量质变仪可获取
transformer_state = data["transformer"]["recovery_time"][
"reached"] # 参量质变仪状态
transformer_recovery_time = data["transformer"]["recovery_time"][
"Day"] # 参量质变仪回复时间
transformer_state = data["transformer"]["recovery_time"]["reached"] # 参量质变仪状态
transformer_recovery_time = data["transformer"]["recovery_time"]["Day"] # 参量质变仪回复时间
transformer_recovery_hour = data["transformer"]["recovery_time"][
"Hour"] # 参量质变仪回复时间
"Hour"
] # 参量质变仪回复时间
coin_minute, coin_second = divmod(int(coin_recovery_time), 60)
coin_hour, coin_minute = divmod(coin_minute, 60)
#print(data)
# print(data)
minute, second = divmod(int(resin_recovery_time), 60)
hour, minute = divmod(minute, 60)
A = BuildImage(1030,
570,
color="#f1e9e1",
font_size=15,
font="HYWenHei-85W.ttf")
A = BuildImage(1030, 570, color="#f1e9e1", font_size=15, font="HYWenHei-85W.ttf")
A.text((10, 15), "原神便笺 | Create By ZhenXun", (198, 186, 177))
ava = BuildImage(100, 100, background=user_avatar)
ava.circle()
A.paste(ava, (40, 40), True)
A.paste(
BuildImage(0,
0,
plain_text=uname,
font_size=20,
font="HYWenHei-85W.ttf"),
BuildImage(0, 0, plain_text=uname, font_size=20, font="HYWenHei-85W.ttf"),
(160, 62),
True,
)
@@ -225,40 +208,39 @@ def _parse_data_and_draw(data: dict, user_avatar: BytesIO, uid: int,
"chengehu.png",
"洞天财翁-洞天宝钱",
"洞天财翁已达到存储上限"
if current_coin == max_coin else f"{coin_hour}小时{coin_minute}分钟后存满",
if current_coin == max_coin
else f"{coin_hour}小时{coin_minute}分钟后存满",
f"{current_coin}/{max_coin}",
)
A.paste(border, (10, 395))
border = create_border(
"zhibian.png",
"参量质变仪",
"不存在" if not transformer_available else
"已准备完成 " if transformer_state else f"{transformer_recovery_hour}小时后可使用" if not transformer_recovery_time else f"{transformer_recovery_time}天后可使用",
"不存在" if not transformer_available else
"可使用" if transformer_state else "冷却中",
"不存在"
if not transformer_available
else "已准备完成 "
if transformer_state
else f"{transformer_recovery_hour}小时后可使用"
if not transformer_recovery_time
else f"{transformer_recovery_time}天后可使用",
"不存在" if not transformer_available else "可使用" if transformer_state else "冷却中",
)
A.paste(border, (10, 475))
expeditions_border = BuildImage(470,
510,
color="#E0D9D1",
font="HYWenHei-85W.ttf",
font_size=20)
expeditions_text = BuildImage(466,
506,
color="#F5F1EB",
font_size=23,
font="HYWenHei-85W.ttf")
expeditions_border = BuildImage(
470, 510, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20
)
expeditions_text = BuildImage(
466, 506, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf"
)
expeditions_text.text(
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}",
(100, 100, 98))
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}", (100, 100, 98)
)
h = 45
for x in expeditions:
_bk = BuildImage(400,
82,
color="#ECE3D8",
font="HYWenHei-85W.ttf",
font_size=21)
_bk = BuildImage(
400, 82, color="#ECE3D8", font="HYWenHei-85W.ttf", font_size=21
)
file_name = x["avatar_side_icon"].split("_")[-1]
role_avatar = memo_path / "role_avatar" / file_name
_ava_img = BuildImage(75, 75, background=role_avatar)
@@ -1,11 +1,13 @@
from httpx import ConnectError
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
from services.log import logger
from .data_source import query_role_data
from .._models import Genshin
from utils.utils import is_number
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageEvent
from nonebot.params import CommandArg
from services.log import logger
from utils.utils import is_number
from .._models import Genshin
from .data_source import query_role_data
__zx_plugin_name__ = "原神玩家查询"
__plugin_usage__ = """
@@ -29,7 +31,9 @@ __plugin_settings__ = {
__plugin_block_limit__ = {}
query_role_info_matcher = on_command("原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True)
query_role_info_matcher = on_command(
"原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True
)
@query_role_info_matcher.handle()
@@ -39,24 +43,25 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
if not is_number(msg):
await query_role_info_matcher.finish("查询uid必须为数字!")
msg = int(msg)
if not msg:
uid = await Genshin.get_user_uid(event.user_id)
uid = None
user = await Genshin.get_or_none(user_qq=event.user_id)
if not msg and user:
uid = user.uid
else:
uid = msg
if not uid: # or not await Genshin.get_user_cookie(uid):
await query_role_info_matcher.finish("请先绑定uid和cookie!")
nickname = event.sender.card or event.sender.nickname
mys_id = await Genshin.get_user_mys_id(uid)
data = await query_role_data(event.user_id, uid, mys_id, nickname)
if data:
await query_role_info_matcher.send(data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神玩家查询 uid:{uid}"
)
else:
await query_role_info_matcher.send("查询失败..")
mys_id = user.mys_id if user else None
try:
data = await query_role_data(event.user_id, uid, mys_id, nickname)
if data:
await query_role_info_matcher.send(data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神玩家查询 uid:{uid}"
)
else:
await query_role_info_matcher.send("查询失败..")
except ConnectError:
await query_role_info_matcher.send("网络出小差啦~")
@@ -1,11 +1,14 @@
from typing import Optional, List, Dict, Union
from .draw_image import init_image, get_genshin_image
from typing import Dict, List, Optional, Tuple, Union
from nonebot.adapters.onebot.v11 import MessageSegment
from .._utils import get_ds, element_mastery
from configs.config import Config
from services.log import logger
from utils.http_utils import AsyncHttpx
from configs.config import Config
from .._models import Genshin
from .._utils import element_mastery, get_ds
from .draw_image import get_genshin_image, init_image
try:
import ujson as json
@@ -96,66 +99,66 @@ b=body q=query
"""
async def get_info(uid_: str, server_id: str) -> "Optional[Union[dict, str]], int":
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
"Origin": "https://webstatic.mihoyo.com",
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.2.0",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"Referer": "https://webstatic.mihoyo.com/app/community-game-records/index.html?v=6",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
"Cookie": await Genshin.get_user_cookie(int(uid_))
},
)
data = req.json()
if data["message"] == "OK":
return data["data"], 200
return data["message"], 999
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
async def get_info(uid_: str, server_id: str) -> Tuple[Optional[Union[dict, str]], int]:
# try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
"Origin": "https://webstatic.mihoyo.com",
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.2.0",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"Referer": "https://webstatic.mihoyo.com/app/community-game-records/index.html?v=6",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
"Cookie": await Genshin.random_cookie(uid_),
},
)
data = req.json()
if data["message"] == "OK":
return data["data"], 200
return data["message"], 999
# except Exception as e:
# logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None, -1
async def get_character(
uid: str, character_ids: List[str], server_id="cn_gf01"
) -> Optional[dict]:
try:
req = await AsyncHttpx.post(
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(
"",
{
"character_ids": character_ids,
"role_id": uid,
"server": server_id,
},
),
"Origin": "https://webstatic.mihoyo.com",
"Cookie": await Genshin.get_user_cookie(int(uid)),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
},
json={"character_ids": character_ids, "role_id": uid, "server": server_id},
)
data = req.json()
if data["message"] == "OK":
return data["data"]
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
# try:
req = await AsyncHttpx.post(
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(
"",
{
"character_ids": character_ids,
"role_id": uid,
"server": server_id,
},
),
"Origin": "https://webstatic.mihoyo.com",
"Cookie": await Genshin.random_cookie(uid),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
},
json={"character_ids": character_ids, "role_id": uid, "server": server_id},
)
data = req.json()
if data["message"] == "OK":
return data["data"]
# except Exception as e:
# logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None
@@ -205,7 +208,7 @@ def parsed_data(
"image": world["icon"],
"name": world["name"],
"offerings": world["offerings"],
"icon": world["icon"]
"icon": world["icon"],
}
world_data_dict[world["name"]] = _x
home_data_list = []
@@ -231,21 +234,21 @@ async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
:param mys_id: 米游社id
"""
if mys_id:
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
headers={
"DS": get_ds(f"uid={mys_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.get_user_cookie(int(uid))
},
)
data = req.json()
if data["message"] == "OK":
return data["data"]["list"]
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
# try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
headers={
"DS": get_ds(f"uid={mys_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.random_cookie(uid),
},
)
data = req.json()
if data["message"] == "OK":
return data["data"]["list"]
# except Exception as e:
# logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None
@@ -1,6 +1,7 @@
from utils.utils import scheduler
from .._models import Genshin
from services.log import logger
from utils.utils import scheduler
from .._models import Genshin
@scheduler.scheduled_job(
@@ -10,7 +11,7 @@ from services.log import logger
)
async def _():
try:
await Genshin.reset_today_query_uid()
await Genshin.all().update(today_query_uid="")
logger.warning(f"重置原神查询记录成功..")
except Exception as e:
logger.error(f"重置原神查询记录失败. {type(e)}:{e}")
@@ -1,12 +1,15 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from apscheduler.jobstores.base import JobLookupError
from services.log import logger
from .init_task import scheduler, add_job
from .._models import Genshin
from nonebot.params import Command
from typing import Tuple
from apscheduler.jobstores.base import JobLookupError
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from nonebot.params import Command
from services.log import logger
from utils.depends import OneCommand
from .._models import Genshin
from .init_task import add_job, scheduler
__zx_plugin_name__ = "原神树脂提醒"
__plugin_usage__ = """
@@ -33,31 +36,32 @@ __plugin_configs__ = {
"AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND": {
"value": True,
"help": "当请求连续三次失败时,关闭用户的树脂提醒",
"default_value": True
"default_value": True,
},
"CUSTOM_RESIN_OVERFLOW_REMIND": {
"value": 20,
"help": "自定义树脂溢出指定数量时的提醒,空值是为关闭",
"default_value": None
}
"default_value": None,
},
}
resin_remind = on_command("开原神树脂提醒", aliases={"关原神树脂提醒"}, priority=5, block=True)
@resin_remind.handle()
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
cmd = cmd[0]
uid = await Genshin.get_user_uid(event.user_id)
if not uid or not await Genshin.get_user_cookie(uid, True):
async def _(event: MessageEvent, cmd: str = OneCommand()):
user = await Genshin.get_or_none(user_qq=event.user_id)
if not user or not user.uid or not user.cookie:
await resin_remind.finish("请先绑定uid和cookie!")
try:
scheduler.remove_job(f"genshin_resin_remind_{uid}_{event.user_id}")
scheduler.remove_job(f"genshin_resin_remind_{user.uid}_{event.user_id}")
except JobLookupError:
pass
if cmd[0] == "开":
await Genshin.set_resin_remind(uid, True)
add_job(event.user_id, uid)
if user.resin_remind:
await resin_remind.finish("原神树脂提醒已经是开启状态,请勿重复开启!", at_sender=True)
user.resin_remind = True
add_job(event.user_id, user.uid)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
@@ -65,12 +69,15 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
)
await resin_remind.send("开启原神树脂提醒成功!", at_sender=True)
else:
await Genshin.set_resin_remind(uid, False)
await Genshin.clear_resin_remind_time(uid)
if not user.resin_remind:
await resin_remind.finish("原神树脂提醒已经是开启状态,请勿重复开启!", at_sender=True)
user.resin_remind = False
user.resin_recovery_time = None
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 关闭原神体力提醒"
)
await resin_remind.send("已关闭原神树脂提醒..", at_sender=True)
if user:
await user.save(update_fields=["resin_remind", "resin_recovery_time"])
@@ -1,20 +1,20 @@
from nonebot.adapters.onebot.v11 import ActionFailed
from utils.utils import get_bot, scheduler
from utils.message_builder import at
from models.group_member_info import GroupInfoUser
from apscheduler.jobstores.base import ConflictingIdError
from nonebot import Driver
from .._models import Genshin
from datetime import datetime, timedelta
from apscheduler.jobstores.base import JobLookupError
from services.log import logger
from nonebot.plugin import require
from configs.config import Config
import random
from datetime import datetime, timedelta
import nonebot
import pytz
from apscheduler.jobstores.base import ConflictingIdError, JobLookupError
from nonebot import Driver
from nonebot.adapters.onebot.v11 import ActionFailed
from nonebot.plugin import require
from configs.config import Config
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.message_builder import at
from utils.utils import get_bot, scheduler
from .._models import Genshin
driver: Driver = nonebot.get_driver()
@@ -23,7 +23,6 @@ require("query_memo")
from ..query_memo import get_memo
global_map = {}
@@ -80,12 +79,13 @@ async def _():
"""
启动时分配定时任务
"""
g_list = await Genshin.get_all_resin_remind_user()
g_list = await Genshin.filter(resin_remind=True).all()
update_list = []
date = datetime.now(pytz.timezone("Asia/Shanghai")) + timedelta(seconds=30)
for u in g_list:
if u.resin_remind:
if u.resin_recovery_time:
if await Genshin.get_user_resin_recovery_time(u.uid) > datetime.now(
if u.resin_recovery_time and u.resin_recovery_time > datetime.now(
pytz.timezone("Asia/Shanghai")
):
# date = await Genshin.get_user_resin_recovery_time(u.uid) # 不能要,因为可能在这期间用户使用了树脂
@@ -101,7 +101,8 @@ async def _():
f"genshin_resin_remind add_job:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
)
else:
await Genshin.clear_resin_remind_time(u.uid)
u.resin_recovery_time = None
update_list.append(u)
add_job(u.user_qq, u.uid)
logger.info(
f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
@@ -111,6 +112,8 @@ async def _():
logger.info(
f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid}启动原神树脂提醒 "
)
if update_list:
await Genshin.bulk_update(update_list, ["resin_recovery_time"])
def add_job(user_id: int, uid: int):
@@ -133,6 +136,7 @@ def add_job(user_id: int, uid: int):
async def _remind(user_id: int, uid: str):
user = await Genshin.get_or_none(user_qq=user_id, uid=int(uid))
uid = str(uid)
if uid[0] in ["1", "2"]:
server_id = "cn_gf01"
@@ -158,7 +162,9 @@ async def _remind(user_id: int, uid: str):
elif max_resin - 20 <= current_resin < max_resin:
next_time = now + timedelta(minutes=(max_resin - current_resin) * 8)
elif current_resin == max_resin:
custom_overflow_resin = Config.get_config("resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND")
custom_overflow_resin = Config.get_config(
"resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND"
)
if user_manager.is_overflow(uid) and custom_overflow_resin:
next_time = now + timedelta(minutes=custom_overflow_resin * 8)
user_manager.add_overflow(uid)
@@ -178,28 +184,35 @@ async def _remind(user_id: int, uid: str):
message=msg,
)
else:
group_id = await Genshin.get_bind_group(int(uid))
if not group_id:
group_list = await GroupInfoUser.get_user_all_group(user_id)
if group_list:
group_id = group_list[0]
try:
await bot.send_group_msg(
group_id=group_id,
message=at(user_id) + msg
)
except ActionFailed as e:
logger.error(f"树脂提醒推送发生错误 {type(e)}:{e}")
if user:
group_id = user.bind_group
if not group_id:
if group_list := await GroupInfoUser.get_user_all_group(
user_id
):
group_id = group_list[0]
try:
await bot.send_group_msg(
group_id=group_id, message=at(user_id) + msg
)
except ActionFailed as e:
logger.error(f"树脂提醒推送发生错误 {type(e)}:{e}")
if not next_time:
if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"):
await Genshin.set_resin_remind(int(uid), False)
await Genshin.clear_resin_remind_time(int(uid))
if user_manager.check(uid) and Config.get_config(
"resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"
):
if user:
user.resin_remind = False
user.resin_recovery_time = None
await user.save(update_fields=["resin_recovery_time", "resin_remind"])
next_time = now + timedelta(minutes=(20 + random.randint(5, 20)) * 8)
user_manager.add_error_count(uid)
else:
user_manager.remove_error_count(uid)
await Genshin.set_user_resin_recovery_time(int(uid), next_time)
if user:
user.resin_recovery_time = next_time
await user.save(update_fields=["resin_recovery_time", "resin_remind"])
scheduler.add_job(
_remind,
"date",
@@ -208,6 +221,5 @@ async def _remind(user_id: int, uid: str):
args=[user_id, uid],
)
logger.info(
f"genshin_resin_remind add_job:USER:{user_id} UID:{uid} "
f"{next_time} 原神树脂提醒"
)
f"genshin_resin_remind add_job:USER:{user_id} UID:{uid} " f"{next_time} 原神树脂提醒"
)
+54 -75
View File
@@ -29,7 +29,6 @@ from nonebot.params import CommandArg
import random
import time
__zx_plugin_name__ = "金币红包"
__plugin_usage__ = """
usage:
@@ -64,11 +63,16 @@ __plugin_settings__ = {
}
__plugin_resources__ = {"prts": IMAGE_PATH}
async def rule(event: GroupMessageEvent) -> bool:
return check_on_gold_red(event)
gold_redbag = on_command(
"塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP
)
open_ = on_command("开", aliases={"抢"}, priority=5, block=True, permission=GROUP)
open_ = on_command("开", aliases={"抢"}, priority=5, block=True, permission=GROUP, rule=rule)
poke_ = on_notice(priority=6, block=False)
@@ -85,27 +89,11 @@ festive_redbag_data = {}
# 阻断其他poke
@run_preprocessor
async def _(matcher: Matcher, event: PokeNotifyEvent):
async def _(matcher: Matcher, event: PokeNotifyEvent, ):
try:
if matcher.type == "notice" and event.self_id == event.target_id:
flag1 = True
flag2 = True
try:
if festive_redbag_data[event.group_id]["user_id"]:
if (
event.user_id
in festive_redbag_data[event.group_id]["open_user"]
):
flag1 = False
except KeyError:
flag1 = False
try:
if redbag_data[event.group_id]["user_id"]:
if event.user_id in redbag_data[event.group_id]["open_user"]:
flag2 = False
except KeyError:
flag2 = False
if flag1 or flag2:
flag = check_on_gold_red(event)
if flag:
if matcher.plugin_name == "poke":
raise IgnoredException("目前正在抢红包...")
else:
@@ -121,8 +109,8 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
try:
if time.time() - redbag_data[event.group_id]["time"] > 60:
amount = (
redbag_data[event.group_id]["amount"]
- redbag_data[event.group_id]["open_amount"]
redbag_data[event.group_id]["amount"]
- redbag_data[event.group_id]["open_amount"]
)
await return_gold(redbag_data[event.group_id]["user_id"], event.group_id, amount)
await gold_redbag.send(
@@ -185,43 +173,21 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
msg = (
msg.replace("!", "")
.replace("!", "")
.replace(",", "")
.replace(",", "")
.replace(".", "")
.replace("。", "")
.replace("!", "")
.replace(",", "")
.replace(",", "")
.replace(".", "")
.replace("。", "")
)
if msg:
if "红包" not in msg:
return
flag1 = True
flag2 = True
open_flag1 = True
open_flag2 = True
try:
if festive_redbag_data[event.group_id]["user_id"]:
if event.user_id in festive_redbag_data[event.group_id]["open_user"]:
open_flag1 = False
except KeyError:
open_flag1 = False
flag1 = False
try:
if redbag_data[event.group_id]["user_id"]:
if event.user_id in redbag_data[event.group_id]["open_user"]:
open_flag2 = False
except KeyError:
flag2 = False
if not flag1 and not flag2:
await open_.finish("目前没有红包可以开...", at_sender=True)
if open_flag1 or open_flag2:
try:
await open_.send(
image(b64=await get_redbag_img(event.user_id, event.group_id)),
at_sender=True,
await open_.send(
image(b64=await get_redbag_img(event.user_id, event.group_id)),
at_sender=True,
)
except KeyError:
await open_.finish("真贪心,明明已经开过这个红包了的说...", at_sender=True)
else:
except KeyError:
await open_.finish("真贪心,明明已经开过这个红包了的说...", at_sender=True)
@@ -229,19 +195,8 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
async def _poke_(event: PokeNotifyEvent):
global redbag_data, festive_redbag_data
if event.self_id == event.target_id:
flag1 = True
flag2 = True
try:
if event.user_id in festive_redbag_data[event.group_id]["open_user"]:
flag1 = False
except KeyError:
flag1 = False
try:
if event.user_id in redbag_data[event.group_id]["open_user"]:
flag2 = False
except KeyError:
flag2 = False
if not flag1 and not flag2:
flag = check_on_gold_red(event)
if not flag:
return
await poke_.send(
image(b64=await get_redbag_img(event.user_id, event.group_id)),
@@ -331,7 +286,7 @@ async def _(bot: Bot, arg: Message = CommandArg()):
await bot.send_group_msg(
group_id=g,
message=f"{NICKNAME}发起了金币红包\n金额:{amount}\n数量:{num}\n"
+ image(
+ image(
b64=await generate_send_redbag_pic(int(bot.self_id), greetings)
),
)
@@ -342,13 +297,13 @@ async def _(bot: Bot, arg: Message = CommandArg()):
# 红包数据初始化
def init_redbag(
user_id: int,
group_id: int,
nickname: str,
amount: int,
num: int,
bot_self_id: int,
mode: int = 0,
user_id: int,
group_id: int,
nickname: str,
amount: int,
num: int,
bot_self_id: int,
mode: int = 0,
):
global redbag_data, festive_redbag_data
data = redbag_data if mode == 0 else festive_redbag_data
@@ -428,3 +383,27 @@ async def end_festive_redbag(bot: Bot, group_id: int):
)
await bot.send_group_msg(group_id=group_id, message=message)
festive_redbag_data[group_id] = {}
def check_on_gold_red(event) -> bool:
flag1 = True
flag2 = True
try:
if festive_redbag_data[event.group_id]["user_id"]:
if (
event.user_id
in festive_redbag_data[event.group_id]["open_user"]
):
flag1 = False
except KeyError:
flag1 = False
try:
if redbag_data[event.group_id]["user_id"]:
if event.user_id in redbag_data[event.group_id]["open_user"]:
flag2 = False
except KeyError:
flag2 = False
if flag1 or flag2:
return True
else:
return False
+41 -56
View File
@@ -1,73 +1,58 @@
from services.db_context import db
from typing import List
from tortoise import fields
class RedbagUser(db.Model):
__tablename__ = "redbag_users"
from services.db_context import Model
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
send_redbag_count = db.Column(db.Integer(), default=0)
get_redbag_count = db.Column(db.Integer(), default=0)
spend_gold = db.Column(db.Integer(), default=0)
get_gold = db.Column(db.Integer(), default=0)
_idx1 = db.Index("redbag_group_users_idx1", "user_qq", "group_id", unique=True)
class RedbagUser(Model):
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
send_redbag_count = fields.IntField(default=0)
"""发送红包次数"""
get_redbag_count = fields.IntField(default=0)
"""开启红包次数"""
spend_gold = fields.IntField(default=0)
"""发送红包花费金额"""
get_gold = fields.IntField(default=0)
"""开启红包获取金额"""
class Meta:
table = "redbag_users"
table_description = "红包统计数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def add_redbag_data(cls, user_qq: int, group_id: int, itype: str, money: int):
async def add_redbag_data(
cls, user_qq: int, group_id: int, i_type: str, money: int
):
"""
说明:
添加收发红包数据
参数:
:param user_qq: qq号
:param group_id: 群号
:param itype: 收或发
:param i_type: 收或发
:param money: 金钱数量
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.with_for_update().gino.first() or await cls.create(
user_qq=user_qq,
group_id=group_id,
)
if itype == "get":
await user.update(
get_redbag_count=user.get_redbag_count + 1,
get_gold=user.get_gold + money,
).apply()
else:
await user.update(
send_redbag_count=user.send_redbag_count + 1,
spend_gold=user.spend_gold + money,
).apply()
@classmethod
async def ensure(cls, user_qq: int, group_id: int) -> bool:
"""
说明:
获取用户对象
参数:
:param user_qq: qq号
:param group_id: 群号
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
user = await query.gino.first() or await cls.create(
user_qq=user_qq,
group_id=group_id,
)
return user
@classmethod
async def get_user_all(cls, group_id: int = None) -> List["RedbagUser"]:
"""
说明:
获取所有用户对象
参数:
:param group_id: 群号
"""
if not group_id:
query = await cls.query.gino.all()
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
if i_type == "get":
user.get_redbag_count = user.get_redbag_count + 1
user.get_gold = user.get_gold + money
else:
query = await cls.query.where((cls.group_id == group_id)).gino.all()
return query
user.send_redbag_count = user.send_redbag_count + 1
user.spend_gold = user.spend_gold + money
await user.save(
update_fields=[
"get_redbag_count",
"get_gold",
"send_redbag_count",
"spend_gold",
]
)
+19 -18
View File
@@ -1,15 +1,17 @@
from nonebot import on_message, on_regex
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from utils.utils import is_number, get_message_text
from services.log import logger
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from utils.utils import FreqLimiter, cn2py
from configs.config import Config
from utils.manager import withdraw_message_manager
from .rule import rule
import random
import os
import random
from nonebot import on_message, on_regex
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from configs.config import Config
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.manager import withdraw_message_manager
from utils.message_builder import image
from utils.utils import FreqLimiter, cn2py, get_message_text, is_number
from .rule import rule
try:
import ujson as json
@@ -66,16 +68,14 @@ async def _(event: MessageEvent):
if len(msg) > 1:
img_id = msg[1]
path = _path / cn2py(gallery)
if gallery in Config.get_config(
"image_management", "IMAGE_DIR_LIST"
):
if gallery in Config.get_config("image_management", "IMAGE_DIR_LIST"):
if not path.exists() and (path.parent.parent / cn2py(gallery)).exists():
path = IMAGE_PATH / cn2py(gallery)
else:
path.mkdir(parents=True, exist_ok=True)
length = len(os.listdir(path))
if length == 0:
logger.warning(f'图库 {cn2py(gallery)} 为空,调用取消!')
logger.warning(f"图库 {cn2py(gallery)} 为空,调用取消!")
await send_img.finish("该图库中没有图片噢")
index = img_id if img_id else str(random.randint(0, length - 1))
if not is_number(index):
@@ -87,8 +87,7 @@ async def _(event: MessageEvent):
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
f"发送{cn2py(gallery)}:"
+ result
f"发送{cn2py(gallery)}:" + result
)
msg_id = await send_img.send(
f"id:{index}" + result
@@ -113,4 +112,6 @@ async def _(event: MessageEvent):
async def _(event: MessageEvent):
if _flmt.check(event.user_id):
_flmt.start_cd(event.user_id)
await pa_reg.finish(image(random.choice(os.listdir(IMAGE_PATH / "pa")), "pa"))
await pa_reg.finish(
image(IMAGE_PATH / "pa" / random.choice(os.listdir(IMAGE_PATH / "pa")))
)
+12 -11
View File
@@ -1,10 +1,11 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11.permission import GROUP
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from models.group_member_info import GroupInfoUser
from datetime import timedelta
from models.level_user import LevelUser
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from nonebot.adapters.onebot.v11.permission import GROUP
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
__zx_plugin_name__ = "个人信息权限查看"
__plugin_usage__ = """
@@ -31,13 +32,13 @@ async def _(event: GroupMessageEvent):
async def get_member_info(user_qq: int, group_id: int) -> str:
user = await GroupInfoUser.get_member_info(user_qq, group_id)
if user is None:
if user := await GroupInfoUser.get_or_none(user_qq=user_qq, group_id=group_id):
result = ""
result += "昵称:" + user.user_name + "\n"
result += "加群时间:" + str(user.user_join_time.date())
return result
else:
return "该群员不在列表中,请更新群成员信息"
result = ""
result += "昵称:" + user.user_name + "\n"
result += "加群时间:" + str(user.user_join_time.date() + timedelta(hours=8))
return result
@my_level.handle()
+15 -27
View File
@@ -1,35 +1,23 @@
from datetime import datetime
from tortoise import fields
from services.db_context import db
from services.db_context import Model
# 1.狂牙武器箱
class BuffPrice(db.Model):
__tablename__ = 'buff_prices'
__table_args__ = {'extend_existing': True}
class BuffPrice(Model):
id = db.Column(db.Integer(), primary_key=True)
case_id = db.Column(db.Integer(), nullable=False)
skin_name = db.Column(db.Unicode(), nullable=False)
skin_price = db.Column(db.Float(), nullable=False)
update_date = db.Column(db.DateTime(), nullable=False)
_idx1 = db.Index('buff_price_idx1', 'skin_name', unique=True)
@classmethod
async def ensure(cls, skin_name: str, for_update: bool = False) -> 'BuffPrice':
query = cls.query.where(
(cls.skin_name == skin_name)
)
if for_update:
query = query.with_for_update()
user = await query.gino.first()
return user or await cls.create(
case_id=1,
skin_name=skin_name,
skin_price=0,
update_date=datetime.min,
)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
case_id = fields.IntField()
"""箱子id"""
skin_name = fields.CharField(255, unique=True)
"""皮肤名称"""
skin_price = fields.FloatField()
"""皮肤价格"""
update_date = fields.DatetimeField()
class Meta:
table = "buff_prices"
table_description = "Buff价格数据表"
+46 -55
View File
@@ -1,60 +1,51 @@
from datetime import datetime
from tortoise import fields
from services.db_context import db
class OpenCasesUser(db.Model):
__tablename__ = 'open_cases_users'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
total_count = db.Column(db.Integer(), nullable=False, default=0)
blue_count = db.Column(db.Integer(), nullable=False, default=0)
blue_st_count = db.Column(db.Integer(), nullable=False, default=0)
purple_count = db.Column(db.Integer(), nullable=False, default=0)
purple_st_count = db.Column(db.Integer(), nullable=False, default=0)
pink_count = db.Column(db.Integer(), nullable=False, default=0)
pink_st_count = db.Column(db.Integer(), nullable=False, default=0)
red_count = db.Column(db.Integer(), nullable=False, default=0)
red_st_count = db.Column(db.Integer(), nullable=False, default=0)
knife_count = db.Column(db.Integer(), nullable=False, default=0)
knife_st_count = db.Column(db.Integer(), nullable=False, default=0)
spend_money = db.Column(db.Integer(), nullable=False, default=0)
make_money = db.Column(db.Float(), nullable=False, default=0)
today_open_total = db.Column(db.Integer(), nullable=False, default=0)
open_cases_time_last = db.Column(db.DateTime(timezone=True), nullable=False, default=datetime.now())
knifes_name = db.Column(db.Unicode(), nullable=False, default="")
_idx1 = db.Index('open_cases_group_users_idx1', 'user_qq', 'group_id', unique=True)
@classmethod
async def ensure(cls, user_qq: int, group_id: int, for_update: bool = False) -> 'OpenCasesUser':
query = cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
if for_update:
query = query.with_for_update()
user = await query.gino.first()
return user or await cls.create(
user_qq=user_qq,
group_id=group_id,
)
@classmethod
async def get_user_all(cls, group_id: int = None) -> 'list':
user_list = []
if not group_id:
query = await cls.query.gino.all()
else:
query = await cls.query.where(
(cls.group_id == group_id)
).gino.all()
for user in query:
user_list.append(user)
return user_list
from services.db_context import Model
class OpenCasesUser(Model):
__tablename__ = "open_cases_users"
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
total_count = fields.IntField(default=0)
"""总开启次数"""
blue_count = fields.IntField(default=0)
"""蓝色"""
blue_st_count = fields.IntField(default=0)
"""蓝色暗金"""
purple_count = fields.IntField(default=0)
"""紫色"""
purple_st_count = fields.IntField(default=0)
"""紫色暗金"""
pink_count = fields.IntField(default=0)
"""粉色"""
pink_st_count = fields.IntField(default=0)
"""粉色暗金"""
red_count = fields.IntField(default=0)
"""紫色"""
red_st_count = fields.IntField(default=0)
"""紫色暗金"""
knife_count = fields.IntField(default=0)
"""金色"""
knife_st_count = fields.IntField(default=0)
"""金色暗金"""
spend_money = fields.IntField(default=0)
"""花费金币"""
make_money = fields.IntField(default=0)
"""赚取金币"""
today_open_total = fields.IntField(default=0)
"""今日开箱数量"""
open_cases_time_last = fields.DatetimeField()
"""最后开箱日期"""
knifes_name = fields.TextField(default="")
"""已获取金色"""
class Meta:
table = "open_cases_users"
table_description = "开箱统计数据表"
unique_together = ("user_qq", "group_id")
+191 -185
View File
@@ -1,20 +1,22 @@
from datetime import datetime, timedelta
from .config import *
from services.log import logger
from services.db_context import db
from .models.open_cases_user import OpenCasesUser
from models.sign_group_user import SignGroupUser
from utils.message_builder import image
import pypinyin
import random
from .utils import get_price
from .models.buff_prices import BuffPrice
from PIL import Image
from utils.image_utils import alpha2white_pil, BuildImage
from configs.path_config import IMAGE_PATH
import asyncio
from utils.utils import cn2py
import random
from datetime import datetime, timedelta
import pypinyin
from PIL import Image
from configs.config import Config
from configs.path_config import IMAGE_PATH
from models.sign_group_user import SignGroupUser
from services.log import logger
from utils.image_utils import BuildImage, alpha2white_pil
from utils.message_builder import image
from utils.utils import cn2py
from .config import *
from .models.buff_prices import BuffPrice
from .models.open_cases_user import OpenCasesUser
from .utils import get_price
async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动") -> str:
@@ -26,71 +28,76 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
case = ""
for i in pypinyin.pinyin(case_name, style=pypinyin.NORMAL):
case += "".join(i)
impression = (await SignGroupUser.ensure(user_qq, group)).impression
user, _ = await SignGroupUser.get_or_create(user_qq=user_qq, group_id=group)
impression = user.impression
rand = random.random()
async with db.transaction():
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
# 一天次数上限
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")
):
return _handle_is_MAX_COUNT()
skin, mosun = get_color_quality(rand, case_name)
# 调侃
if skin[:2] == "军规":
if skin.find("StatTrak") == -1:
uplist[0] = 1
else:
uplist[1] = 1
ridicule_result = random.choice(["这样看着才舒服", "是自己人,大伙把刀收好", "非常舒适~"])
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] = 1
else:
uplist[3] = 1
ridicule_result = random.choice(
["还行吧,勉强接受一下下", "居然不是蓝色,太假了", "运气-1-1-1-1-1..."]
)
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] = 1
else:
uplist[5] = 1
ridicule_result = random.choice(
["开始不适....", "你妈妈买菜必涨价!涨三倍!", "你最近不适合出门,真的"]
)
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] = 1
else:
uplist[7] = 1
ridicule_result = random.choice(
["已经非常不适", "好兄弟你开的什么箱子啊,一般箱子不是只有蓝色的吗", "开始拿阳寿开箱子了?"]
)
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] = 1
else:
uplist[9] = 1
ridicule_result = random.choice(
["你的好运我收到了,你可以去喂鲨鱼了", "最近该吃啥就迟点啥吧,哎,好好的一个人怎么就....哎", "众所周知,欧皇寿命极短."]
)
if skin.find("(") != -1:
cskin = skin.split("(")
skin = cskin[0].strip() + "(" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
if skin.find("无涂装") == -1:
dbprice = await BuffPrice.ensure(skin[9:])
await OpenCasesUser.get_or_none(user_qq=user_qq, group_id=group)
# user, _ = await OpenCasesUser.get_or_create(user_qq=user_qq, group_id=group)
user = await OpenCasesUser.get_or_none(user_qq=user_qq, group_id=group)
if not user:
user = await OpenCasesUser.create(
user_qq=user_qq, group_id=group, open_cases_time_last=datetime.now()
)
# 一天次数上限
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")
):
return _handle_is_MAX_COUNT()
skin, mosun = get_color_quality(rand, case_name)
# 调侃
if skin[:2] == "军规":
if skin.find("StatTrak") == -1:
uplist[0] = 1
else:
dbprice = await BuffPrice.ensure(skin[9 : skin.rfind("(")].strip())
if dbprice.skin_price != 0:
price_result = dbprice.skin_price
logger.info("数据库查询到价格: ", dbprice.skin_price)
uplist[10] = dbprice.skin_price
uplist[1] = 1
ridicule_result = random.choice(["这样看着才舒服", "是自己人,大伙把刀收好", "非常舒适~"])
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] = 1
else:
uplist[3] = 1
ridicule_result = random.choice(
["还行吧,勉强接受一下下", "居然不是蓝色,太假了", "运气-1-1-1-1-1..."]
)
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] = 1
else:
uplist[5] = 1
ridicule_result = random.choice(["开始不适....", "你妈妈买菜必涨价!涨三倍!", "你最近不适合出门,真的"])
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] = 1
else:
uplist[7] = 1
ridicule_result = random.choice(
["已经非常不适", "好兄弟你开的什么箱子啊,一般箱子不是只有蓝色的吗", "开始拿阳寿开箱子了?"]
)
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] = 1
else:
uplist[9] = 1
ridicule_result = random.choice(
["你的好运我收到了,你可以去喂鲨鱼了", "最近该吃啥就迟点啥吧,哎,好好的一个人怎么就....哎", "众所周知,欧皇寿命极短."]
)
if skin.find("(") != -1:
cskin = skin.split("(")
skin = cskin[0].strip() + "(" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
if skin.find("无涂装") == -1:
search_name = skin[9:]
else:
search_name = skin[9 : skin.rfind("(")].strip()
price_result = 0
if data := await BuffPrice.get_or_none(skin_name=search_name):
if data.skin_price != 0:
price_result = data.skin_price
logger.info("数据库查询到价格: ", data.skin_price)
uplist[10] = data.skin_price
else:
price = -1
price_result = "未查询到"
@@ -102,55 +109,56 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
price = float(pcp[1].strip())
break
if price != -1:
logger.info("存储入数据库---->", price)
logger.info("存储入数据库---->{price}")
uplist[10] = price
price_result = str(price)
await dbprice.update(
skin_price=price,
update_date=datetime.now(),
).apply()
# sp = skin.split("|")
# cskin_word = sp[1][:sp[1].find("(") - 1].strip()
if knifes_flag:
await user.update(
knifes_name=user.knifes_name
+ f"{case}||{skin.split(':')[1].strip()} 磨损:{str(mosun)[:11]}, 价格:{uplist[10]},"
).apply()
cskin_word = skin.split(":")[1].replace("|", "-").replace("(StatTrak™)", "")
cskin_word = cskin_word[: cskin_word.rfind("(")].strip()
skin_name = cn2py(
cskin_word.replace("|", "-").replace("(StatTrak™)", "").strip()
data.skin_price = price
data.update_date = datetime.now()
await data.save(update_fields=["skin_price", "update_date"])
# sp = skin.split("|")
# cskin_word = sp[1][:sp[1].find("(") - 1].strip()
if knifes_flag:
await user.update(
knifes_name=user.knifes_name
+ f"{case}||{skin.split(':')[1].strip()} 磨损:{str(mosun)[:11]}, 价格:{uplist[10]},"
).apply()
cskin_word = skin.split(":")[1].replace("|", "-").replace("(StatTrak™)", "")
cskin_word = cskin_word[: cskin_word.rfind("(")].strip()
skin_name = cn2py(cskin_word.replace("|", "-").replace("(StatTrak™)", "").strip())
img = image(IMAGE_PATH / "cases" / case / f"{skin_name}.png")
# if knifes_flag:
# await user.update(
# knifes_name=user.knifes_name + f"{skin} 磨损:{mosun}, 价格:{uplist[10]}"
# ).apply()
if await update_user_total(user, uplist):
logger.info(
f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}, 数据更新成功"
)
img = image(f"{skin_name}.png", "cases/" + case)
# if knifes_flag:
# await user.update(
# knifes_name=user.knifes_name + f"{skin} 磨损:{mosun}, 价格:{uplist[10]}"
# ).apply()
if await update_user_total(user, uplist):
logger.info(
f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}, 数据更新成功"
)
else:
logger.warning(
f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}, 数据更新失败"
)
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
over_count = int(
else:
logger.warning(
f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}, 数据更新失败"
)
user, _ = await OpenCasesUser.get_or_create(user_qq=user_qq, group_id=group)
over_count = (
int(
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ int(impression)
/ Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
) - user.today_open_total
return (
f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n" + img + "\n" + f"皮肤:{skin}\n"
f"磨损:{mosun:.9f}\n"
f"价格:{price_result}\n"
f"{ridicule_result}"
)
- user.today_open_total
)
return (
f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n" + img + "\n" + f"皮肤:{skin}\n"
f"磨损:{mosun:.9f}\n"
f"价格:{price_result}\n"
f"{ridicule_result}"
)
async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int = 10):
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
impression = (await SignGroupUser.ensure(user_qq, group)).impression
user, _ = await OpenCasesUser.get_or_create(user_qq=user_qq, group_id=group)
sign_user, _ = await SignGroupUser.get_or_create(user_qq=user_qq, group_id=group)
impression = sign_user.impression
max_count = int(
Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ int(impression) / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
@@ -162,11 +170,10 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
f"今天开箱次数不足{num}次噢,请单抽试试看(也许单抽运气更好?)"
f"\n剩余开箱次数:{max_count - user.today_open_total}"
)
await user.update(
total_count=user.total_count + num,
spend_money=user.spend_money + 17 * num,
today_open_total=user.today_open_total + num,
).apply()
user.total_count = user.total_count + num
user.spend_money = user.spend_money + 17 * num
user.today_open_total = user.today_open_total + num
await user.save(update_fields=["total_count", "spend_money", "today_open_total"])
if num < 5:
h = 270
elif num % 5 == 0:
@@ -180,46 +187,46 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
uplist = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0]
img_list = []
name_list = ["蓝", "蓝(暗金)", "紫", "紫(暗金)", "粉", "粉(暗金)", "红", "红(暗金)", "金", "金(暗金)"]
async with db.transaction():
for _ in range(num):
knifes_flag = False
rand = random.random()
skin, mosun = get_color_quality(rand, case_name)
if skin[:2] == "军规":
if skin.find("StatTrak") == -1:
uplist[0] += 1
else:
uplist[1] += 1
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] += 1
else:
uplist[3] += 1
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] += 1
else:
uplist[5] += 1
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] += 1
else:
uplist[7] += 1
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] += 1
else:
uplist[9] += 1
if skin.find("(") != -1:
cskin = skin.split("(")
skin = cskin[0].strip() + "(" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
if skin.find("无涂装") == -1:
dbprice = await BuffPrice.ensure(skin[9:])
for _ in range(num):
knifes_flag = False
rand = random.random()
skin, mosun = get_color_quality(rand, case_name)
if skin[:2] == "军规":
if skin.find("StatTrak") == -1:
uplist[0] += 1
else:
dbprice = await BuffPrice.ensure(skin[9 : skin.rfind("(")].strip())
uplist[1] += 1
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] += 1
else:
uplist[3] += 1
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] += 1
else:
uplist[5] += 1
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] += 1
else:
uplist[7] += 1
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] += 1
else:
uplist[9] += 1
if skin.find("(") != -1:
cskin = skin.split("(")
skin = cskin[0].strip() + "(" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
if skin.find("无涂装") == -1:
search_name = skin[9:]
else:
search_name = skin[9 : skin.rfind("(")].strip()
if dbprice := await BuffPrice.get_or_none(skin_name=search_name):
if dbprice.skin_price != 0:
price_result = dbprice.skin_price
uplist[10] += price_result
@@ -238,7 +245,6 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
style=pypinyin.NORMAL,
):
skin_name += "".join(i)
# img = image(skin_name, "cases/" + case, "png")
wImg = BuildImage(200, 270, 200, 200)
wImg.paste(
alpha2white_pil(
@@ -296,7 +302,7 @@ def _handle_is_MAX_COUNT() -> str:
async def update_user_total(user: OpenCasesUser, up_list: list, num: int = 1) -> bool:
try:
await user.update(
await user.update_or_create(
total_count=user.total_count + num,
blue_count=user.blue_count + up_list[0],
blue_st_count=user.blue_st_count + up_list[1],
@@ -312,36 +318,35 @@ async def update_user_total(user: OpenCasesUser, up_list: list, num: int = 1) ->
make_money=user.make_money + up_list[10],
today_open_total=user.today_open_total + num,
open_cases_time_last=datetime.now(),
).apply()
)
return True
except:
return False
async def total_open_statistics(user_qq: int, group: int) -> str:
async with db.transaction():
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
return (
f"开箱总数:{user.total_count}\n"
f"今日开箱:{user.today_open_total}\n"
f"蓝色军规:{user.blue_count}\n"
f"蓝色暗金:{user.blue_st_count}\n"
f"紫色受限:{user.purple_count}\n"
f"紫色暗金:{user.purple_st_count}\n"
f"粉色保密:{user.pink_count}\n"
f"粉色暗金:{user.pink_st_count}\n"
f"红色隐秘:{user.red_count}\n"
f"红色暗金:{user.red_st_count}\n"
f"金色罕见:{user.knife_count}\n"
f"金色暗金:{user.knife_st_count}\n"
f"花费金额:{user.spend_money}\n"
f"获取金额:{user.make_money:.2f}\n"
f"最后开箱日期:{(user.open_cases_time_last + timedelta(hours=8)).date()}"
)
user, _ = await OpenCasesUser.get_or_create(user_qq=user_qq, group_id=group)
return (
f"开箱总数:{user.total_count}\n"
f"今日开箱:{user.today_open_total}\n"
f"蓝色军规:{user.blue_count}\n"
f"蓝色暗金:{user.blue_st_count}\n"
f"紫色受限:{user.purple_count}\n"
f"紫色暗金:{user.purple_st_count}\n"
f"粉色保密:{user.pink_count}\n"
f"粉色暗金:{user.pink_st_count}\n"
f"红色隐秘:{user.red_count}\n"
f"红色暗金:{user.red_st_count}\n"
f"金色罕见:{user.knife_count}\n"
f"金色暗金:{user.knife_st_count}\n"
f"花费金额:{user.spend_money}\n"
f"获取金额:{user.make_money:.2f}\n"
f"最后开箱日期:{user.open_cases_time_last.date()}"
)
async def group_statistics(group: int):
user_list = await OpenCasesUser.get_user_all(group)
user_list = await OpenCasesUser.filter(group_id=group).all()
# lan zi fen hong jin pricei
uplist = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0]
for user in user_list:
@@ -377,7 +382,8 @@ async def group_statistics(group: int):
async def my_knifes_name(user_id: int, group: int):
knifes_name = (await OpenCasesUser.ensure(user_id, group)).knifes_name
user, _ = await OpenCasesUser.get_or_create(user_qq=user_id, group_id=group)
knifes_name = user.knifes_name
if knifes_name:
knifes_list = knifes_name[:-1].split(",")
length = len(knifes_list)
+124 -125
View File
@@ -1,17 +1,19 @@
from .models.buff_prices import BuffPrice
from services.db_context import db
from datetime import datetime, timedelta
from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx
from .models.open_cases_user import OpenCasesUser
from services.log import logger
from utils.utils import get_bot, cn2py
from asyncio.exceptions import TimeoutError
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import Config
from utils.manager import group_manager
from .config import *
import os
from asyncio.exceptions import TimeoutError
from datetime import datetime, timedelta
from nonebot.adapters.onebot.v11 import ActionFailed
from configs.config import Config
from configs.path_config import IMAGE_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.manager import group_manager
from utils.utils import cn2py, get_bot
from .config import *
from .models.buff_prices import BuffPrice
from .models.open_cases_user import OpenCasesUser
url = "https://buff.163.com/api/market/goods"
# proxies = 'http://49.75.59.242:3128'
@@ -49,108 +51,102 @@ async def util_get_buff_price(case_name: str = "狂牙大行动") -> str:
"骷髅匕首 | 无涂装",
]:
skin = skin.split("|")[0].strip()
async with db.transaction():
name_list = []
price_list = []
parameter = {"game": "csgo", "page_num": "1", "search": skin}
try:
response = await AsyncHttpx.get(url, proxy=Config.get_config("open_cases", "BUFF_PROXY"),
name_list = []
price_list = []
parameter = {"game": "csgo", "page_num": "1", "search": skin}
try:
response = await AsyncHttpx.get(
url,
proxy=Config.get_config("open_cases", "BUFF_PROXY"),
params=parameter,
cookies=cookie,)
if response.status_code == 200:
data = response.json()["data"]
total_page = data["total_page"]
data = data["items"]
flag = False
if (
skin.find("|") == -1
): # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
for i in range(1, total_page + 1):
name_list = []
price_list = []
parameter = {
"game": "csgo",
"page_num": f"{i}",
"search": skin,
}
res = await AsyncHttpx.get(url, params=parameter, cookies=cookie)
data = res.json()["data"][
"items"
]
for j in range(len(data)):
if data[j]["name"] in [f"{skin}(★)"]:
name = data[j]["name"]
price = data[j][
"sell_reference_price"
]
name_list.append(
name.split("(")[0].strip()
+ " | 无涂装"
)
price_list.append(price)
flag = True
break
if flag:
cookies=cookie,
)
if response.status_code == 200:
data = response.json()["data"]
total_page = data["total_page"]
data = data["items"]
flag = False
if (
skin.find("|") == -1
): # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
for i in range(1, total_page + 1):
name_list = []
price_list = []
parameter = {
"game": "csgo",
"page_num": f"{i}",
"search": skin,
}
res = await AsyncHttpx.get(
url, params=parameter, cookies=cookie
)
data = res.json()["data"]["items"]
for j in range(len(data)):
if data[j]["name"] in [f"{skin}(★)"]:
name = data[j]["name"]
price = data[j]["sell_reference_price"]
name_list.append(
name.split("(")[0].strip() + " | 无涂装"
)
price_list.append(price)
flag = True
break
else:
try:
for _ in range(total_page):
for i in range(len(data)):
name = data[i]["name"]
price = data[i]["sell_reference_price"]
name_list.append(name)
price_list.append(price)
except Exception as e:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
if flag:
break
else:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
except Exception:
try:
for _ in range(total_page):
for i in range(len(data)):
name = data[i]["name"]
price = data[i]["sell_reference_price"]
name_list.append(name)
price_list.append(price)
except Exception as e:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
else:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
continue
for i in range(len(name_list)):
name = name_list[i].strip()
price = float(price_list[i])
if name.find("(★)") != -1:
name = name[: name.find("(")] + name[name.find(")") + 1 :]
if name.find("消音") != -1 and name.find("(S") != -1:
name = name.split("(")[0][:-4] + "(" + name.split("(")[1]
name = (
name.split("|")[0].strip()
+ " | "
+ name.split("|")[1].strip()
)
elif name.find("消音") != -1:
name = (
name.split("|")[0][:-5].strip()
+ " | "
+ name.split("|")[1].strip()
)
if name.find(" 18 ") != -1 and name.find("(S") != -1:
name = name.split("(")[0][:-5] + "(" + name.split("(")[1]
name = (
name.split("|")[0].strip()
+ " | "
+ name.split("|")[1].strip()
)
elif name.find(" 18 ") != -1:
name = (
name.split("|")[0][:-6].strip()
+ " | "
+ name.split("|")[1].strip()
)
dbskin = await BuffPrice.ensure(name, True)
if (
dbskin.update_date + timedelta(8)
).date() == datetime.now().date():
except Exception:
failed_list.append(skin)
logger.warning(f"{skin}更新失败")
continue
for i in range(len(name_list)):
name = name_list[i].strip()
price = float(price_list[i])
if name.find("(★)") != -1:
name = name[: name.find("(")] + name[name.find(")") + 1 :]
if name.find("消音") != -1 and name.find("(S") != -1:
name = name.split("(")[0][:-4] + "(" + name.split("(")[1]
name = (
name.split("|")[0].strip() + " | " + name.split("|")[1].strip()
)
elif name.find("消音") != -1:
name = (
name.split("|")[0][:-5].strip()
+ " | "
+ name.split("|")[1].strip()
)
if name.find(" 18 ") != -1 and name.find("(S") != -1:
name = name.split("(")[0][:-5] + "(" + name.split("(")[1]
name = (
name.split("|")[0].strip() + " | " + name.split("|")[1].strip()
)
elif name.find(" 18 ") != -1:
name = (
name.split("|")[0][:-6].strip()
+ " | "
+ name.split("|")[1].strip()
)
if dbskin := await BuffPrice.get_or_none(skin_name=name):
if dbskin.update_date.date() == datetime.now().date():
continue
await dbskin.update(
case_id=case_id,
skin_price=price,
update_date=datetime.now(),
).apply()
dbskin.case_id = case_id
dbskin.skin_price = price
dbskin.update_date = datetime.now()
await dbskin.save(
update_fields=["case_id", "skin_price", "update_date"]
)
logger.info(f"{name_list[i]}---------->成功更新")
result = None
if failed_list:
@@ -186,14 +182,16 @@ async def util_get_buff_img(case_name: str = "狂牙大行动") -> str:
logger.info(f"开始更新----->{skin}")
skin_name = ""
# try:
response = await AsyncHttpx.get(url, proxy=Config.get_config("open_cases", "BUFF_PROXY"), params=parameter)
response = await AsyncHttpx.get(
url,
proxy=Config.get_config("open_cases", "BUFF_PROXY"),
params=parameter,
)
if response.status_code == 200:
data = response.json()["data"]
total_page = data["total_page"]
flag = False
if (
skin.find("|") == -1
): # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
if skin.find("|") == -1: # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
for i in range(1, total_page + 1):
res = await AsyncHttpx.get(url, params=parameter)
data = res.json()["data"]["items"]
@@ -201,17 +199,21 @@ async def util_get_buff_img(case_name: str = "狂牙大行动") -> str:
if data[j]["name"] in [f"{skin}(★)"]:
img_url = data[j]["goods_info"]["icon_url"]
skin_name = cn2py(skin + "无涂装")
await AsyncHttpx.download_file(img_url, path / f"{skin_name}.png")
await AsyncHttpx.download_file(
img_url, path / f"{skin_name}.png"
)
flag = True
break
if flag:
break
else:
img_url = (await response.json())["data"]["items"][0][
"goods_info"
]["icon_url"]
img_url = (await response.json())["data"]["items"][0]["goods_info"][
"icon_url"
]
skin_name += cn2py(skin.replace("|", "-").strip())
if await AsyncHttpx.download_file(img_url, path / f"{skin_name}.png"):
if await AsyncHttpx.download_file(
img_url, path / f"{skin_name}.png"
):
logger.info(f"------->写入 {skin} 成功")
else:
logger.info(f"------->写入 {skin} 失败")
@@ -255,18 +257,15 @@ async def get_price(d_name):
async def update_count_daily():
try:
users = await OpenCasesUser.get_user_all()
if users:
for user in users:
await user.update(
today_open_total=0,
).apply()
await OpenCasesUser.all().update(today_open_total=0)
bot = get_bot()
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
for g in gl:
try:
await bot.send_group_msg(group_id=g, message="[[_task|open_case_reset_remind]]今日开箱次数重置成功")
await bot.send_group_msg(
group_id=g, message="[[_task|open_case_reset_remind]]今日开箱次数重置成功"
)
except ActionFailed:
logger.warning(f"{g} 群被禁言,无法发送 开箱重置提醒")
logger.info("今日开箱次数重置成功")
+37 -34
View File
@@ -1,22 +1,24 @@
from nonebot import on_message
from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent, ActionFailed
from utils.manager import group_manager
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 aiohttp
import ujson as json
from bilireq import video
from nonebot import on_message
from nonebot.adapters.onebot.v11 import ActionFailed, GroupMessageEvent
from nonebot.adapters.onebot.v11.permission import GROUP
from configs.config import Config
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from utils.browser import get_browser
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from utils.manager import group_manager
from utils.message_builder import image
from utils.user_agent import get_user_agent
from utils.utils import get_local_proxy, get_message_json, get_message_text, is_number
__zx_plugin_name__ = "B站转发解析"
__plugin_usage__ = """
usage:
@@ -39,7 +41,10 @@ Config.add_plugin_config(
async def plugin_on_checker(event: GroupMessageEvent) -> bool:
return group_manager.get_plugin_status("parse_bilibili_json", event.group_id)
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False, rule=plugin_on_checker)
parse_bilibili_json = on_message(
priority=1, permission=GROUP, block=False, rule=plugin_on_checker
)
_tmp = {}
@@ -55,16 +60,14 @@ async def _(event: GroupMessageEvent):
data = None
if data:
# 转发视频
if data.get("desc") == "哔哩哔哩" or data.get('prompt').find('哔哩哔哩') != -1:
async with aiohttp.ClientSession(
headers=get_user_agent()
) as session:
if data.get("desc") == "哔哩哔哩" or "哔哩哔哩" in data.get("prompt"):
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
data["meta"]["detail_1"]["qqdocurl"],
timeout=7,
data["meta"]["detail_1"]["qqdocurl"],
timeout=7,
) as response:
url = str(response.url).split("?")[0]
if url[-1] == '/':
if url[-1] == "/":
url = url[:-1]
bvid = url.split("/")[-1]
vd_info = await video.get_video_base_info(bvid)
@@ -93,10 +96,11 @@ async def _(event: GroupMessageEvent):
timeout=100000,
)
await asyncio.get_event_loop().run_in_executor(
None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
None, resize, TEMP_PATH / f"cv_{event.user_id}.png"
)
await parse_bilibili_json.send(
"[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
"[[_task|bilibili_parse]]"
+ image(TEMP_PATH / f"cv_{event.user_id}.png")
)
await page.close()
logger.info(
@@ -121,15 +125,13 @@ async def _(event: GroupMessageEvent):
msg = msg[index + 2 : index + 11]
if is_number(msg):
url = f"https://www.bilibili.com/video/av{msg}"
vd_info = await video.get_video_base_info('av' + msg)
vd_info = await video.get_video_base_info("av" + 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:
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,
url,
timeout=7,
) as response:
url = (str(response.url).split("?")[0]).strip("/")
bvid = url.split("/")[-1]
@@ -150,8 +152,9 @@ async def _(event: GroupMessageEvent):
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"
"[[_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"
+10 -10
View File
@@ -1,17 +1,17 @@
from asyncio.exceptions import TimeoutError
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import Arg, CommandArg
from nonebot.typing import T_State
from configs.config import Config
from utils.utils import is_number, change_pixiv_image_links
from utils.message_builder import image
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from asyncio.exceptions import TimeoutError
from configs.path_config import IMAGE_PATH
from utils.manager import withdraw_message_manager
from utils.http_utils import AsyncHttpx
from nonebot.params import CommandArg, Arg
from utils.manager import withdraw_message_manager
from utils.message_builder import image
from utils.utils import change_pixiv_image_links, is_number
__zx_plugin_name__ = "pid搜索"
__plugin_usage__ = """
@@ -88,7 +88,7 @@ async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
img_url = change_pixiv_image_links(img_url)
if not await AsyncHttpx.download_file(
img_url,
IMAGE_PATH / "temp" / f"pid_search_{event.user_id}_{i}.png",
TEMP_PATH / f"pid_search_{event.user_id}_{i}.png",
headers=headers,
):
await pid_search.send("图片下载失败了....", at_sender=True)
@@ -101,7 +101,7 @@ async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
f"pid:{pid}\n"
f"author:{author}\n"
f"author_id:{author_id}\n"
f'{image(f"pid_search_{event.user_id}_{i}.png", "temp")}'
f'{image(TEMP_PATH / f"pid_search_{event.user_id}_{i}.png")}'
f"{tmp}"
)
)
+10 -27
View File
@@ -1,7 +1,7 @@
from configs.config import Config
from utils.utils import GDict
import nonebot
from configs.config import Config
from utils.utils import GDict
Config.add_plugin_config(
"hibiapi",
@@ -10,59 +10,42 @@ Config.add_plugin_config(
help_="如果没有自建或其他hibiapi请不要修改",
default_value="https://api.obfs.dev",
)
Config.add_plugin_config(
"pixiv",
"PIXIV_NGINX_URL",
"i.pximg.cf",
help_="Pixiv反向代理"
)
Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pximg.cf", help_="Pixiv反向代理")
Config.add_plugin_config(
"pix",
"PIX_IMAGE_SIZE",
"master",
name="PIX图库",
help_="PIX图库下载的画质 可能的值:original:原图,master:缩略图(加快发送速度)",
default_value="master"
default_value="master",
)
Config.add_plugin_config(
"pix",
"SEARCH_HIBIAPI_BOOKMARKS",
5000,
help_="最低收藏,PIX使用HIBIAPI搜索图片时达到最低收藏才会添加至图库",
default_value=5000
default_value=5000,
)
Config.add_plugin_config(
"pix",
"WITHDRAW_PIX_MESSAGE",
(0, 1),
help_="自动撤回,参1:延迟撤回色图时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)",
default_value=(0, 1)
default_value=(0, 1),
)
Config.add_plugin_config(
"pix",
"PIX_OMEGA_PIXIV_RATIO",
(10, 0),
help_="PIX图库 与 额外图库OmegaPixivIllusts 混合搜索的比例 参1:PIX图库 参2:OmegaPixivIllusts扩展图库(没有此图库请设置为0)",
default_value=(10, 0)
)
Config.add_plugin_config(
"pix",
"TIMEOUT",
10,
help_="下载图片超时限制(秒)",
default_value=10
default_value=(10, 0),
)
Config.add_plugin_config("pix", "TIMEOUT", 10, help_="下载图片超时限制(秒)", default_value=10)
Config.add_plugin_config(
"pix",
"SHOW_INFO",
True,
help_="是否显示图片的基本信息,如PID等",
default_value=True
"pix", "SHOW_INFO", True, help_="是否显示图片的基本信息,如PID等", default_value=True
)
GDict['run_sql'].append("ALTER TABLE omega_pixiv_illusts ADD classified Integer;")
GDict["run_sql"].append("ALTER TABLE omega_pixiv_illusts ADD classified Integer;")
nonebot.load_plugins("plugins/pix_gallery")
+123 -116
View File
@@ -1,19 +1,23 @@
from asyncpg.exceptions import UniqueViolationError
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
from asyncio.locks import Semaphore
from asyncio.exceptions import TimeoutError
from ._model.pixiv import Pixiv
from typing import List, Optional
from utils.utils import change_pixiv_image_links, change_img_md5
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
from services.log import logger
from configs.config import Config
from configs.path_config import TEMP_PATH
import aiofiles
import platform
import asyncio
import math
import platform
from asyncio.exceptions import TimeoutError
from asyncio.locks import Semaphore
from copy import deepcopy
from typing import List, Optional, Tuple
import aiofiles
from asyncpg.exceptions import UniqueViolationError
from configs.config import Config
from configs.path_config import TEMP_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage
from utils.utils import change_img_md5, change_pixiv_image_links
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
from ._model.pixiv import Pixiv
try:
import ujson as json
@@ -65,9 +69,7 @@ async def start_update_image_url(
params = {"word": keyword, "page": page}
tasks.append(
asyncio.ensure_future(
search_image(
url, keyword, params, semaphore, page, black_pid
)
search_image(url, keyword, params, semaphore, page, black_pid)
)
)
if keyword.startswith("pid:"):
@@ -101,96 +103,91 @@ async def search_image(
pic_count = 0
pid_count = 0
async with semaphore:
try:
data = (await AsyncHttpx.get(url, params=params)).json()
if (
not data
or data.get("error")
or (not data.get("illusts") and not data.get("illust"))
):
return 0, 0
if url != f"{HIBIAPI}/api/pixiv/illust":
logger.info(f'{keyword}: 获取数据成功...数据总量:{len(data["illusts"])}')
data = data["illusts"]
# try:
data = (await AsyncHttpx.get(url, params=params)).json()
if (
not data
or data.get("error")
or (not data.get("illusts") and not data.get("illust"))
):
return 0, 0
if url != f"{HIBIAPI}/api/pixiv/illust":
logger.info(f'{keyword}: 获取数据成功...数据总量:{len(data["illusts"])}')
data = data["illusts"]
else:
logger.info(f'获取数据成功...PID:{params.get("id")}')
data = [data["illust"]]
img_data = {}
for x in data:
pid = x["id"]
title = x["title"]
width = x["width"]
height = x["height"]
view = x["total_view"]
bookmarks = x["total_bookmarks"]
uid = x["user"]["id"]
author = x["user"]["name"]
tags = []
for tag in x["tags"]:
for i in tag:
if tag[i]:
tags.append(tag[i])
img_urls = []
if x["page_count"] == 1:
img_urls.append(x["meta_single_page"]["original_image_url"])
else:
logger.info(f'获取数据成功...PID:{params.get("id")}')
data = [data["illust"]]
img_data = {}
for x in data:
pid = x["id"]
title = x["title"]
width = x["width"]
height = x["height"]
view = x["total_view"]
bookmarks = x["total_bookmarks"]
uid = x["user"]["id"]
author = x["user"]["name"]
tags = []
for tag in x["tags"]:
for i in tag:
if tag[i]:
tags.append(tag[i])
img_urls = []
if x["page_count"] == 1:
img_urls.append(x["meta_single_page"]["original_image_url"])
else:
for urls in x["meta_pages"]:
img_urls.append(urls["image_urls"]["original"])
if (
(
bookmarks
>= Config.get_config("pix", "SEARCH_HIBIAPI_BOOKMARKS")
or (
url == f"{HIBIAPI}/api/pixiv/member_illust"
and bookmarks >= 1500
)
or (url == f"{HIBIAPI}/api/pixiv/illust")
for urls in x["meta_pages"]:
img_urls.append(urls["image_urls"]["original"])
if (
(
bookmarks >= Config.get_config("pix", "SEARCH_HIBIAPI_BOOKMARKS")
or (
url == f"{HIBIAPI}/api/pixiv/member_illust"
and bookmarks >= 1500
)
and len(img_urls) < 10
and _check_black(img_urls, black)
or (url == f"{HIBIAPI}/api/pixiv/illust")
)
and len(img_urls) < 10
and _check_black(img_urls, black)
):
img_data[pid] = {
"pid": pid,
"title": title,
"width": width,
"height": height,
"view": view,
"bookmarks": bookmarks,
"img_urls": img_urls,
"uid": uid,
"author": author,
"tags": tags,
}
else:
continue
for x in img_data.keys():
data = img_data[x]
data_copy = deepcopy(data)
del data_copy["img_urls"]
for img_url in data["img_urls"]:
img_p = img_url[img_url.rfind("_") + 1 : img_url.rfind(".")]
data_copy["img_url"] = img_url
data_copy["img_p"] = img_p
data_copy["is_r18"] = "R-18" in data["tags"]
if not await Pixiv.exists(
pid=data["pid"], img_url=img_url, img_p=img_p
):
img_data[pid] = {
"pid": pid,
"title": title,
"width": width,
"height": height,
"view": view,
"bookmarks": bookmarks,
"img_urls": img_urls,
"uid": uid,
"author": author,
"tags": tags,
}
data_copy["img_url"] = img_url
await Pixiv.create(**data_copy)
if data["pid"] not in tmp_pid:
pid_count += 1
tmp_pid.append(data["pid"])
pic_count += 1
logger.info(f'存储图片PID:{data["pid"]} IMG_P:{img_p}')
else:
continue
for x in img_data.keys():
data = img_data[x]
for img_url in data["img_urls"]:
img_p = img_url[img_url.rfind("_") + 1 : img_url.rfind(".")]
try:
if await Pixiv.add_image_data(
data["pid"],
data["title"],
data["width"],
data["height"],
data["view"],
data["bookmarks"],
img_url,
img_p,
data["uid"],
data["author"],
",".join(data["tags"]),
):
if data["pid"] not in tmp_pid:
pid_count += 1
tmp_pid.append(data["pid"])
pic_count += 1
logger.info(f'存储图片PID:{data["pid"]} IMG_P:{img_p}')
except UniqueViolationError:
logger.warning(f'{data["pid"]} | {img_url} 已存在...')
except Exception as e:
logger.warning(f"PIX在线搜索图片错误,已再次调用 {type(e)}:{e}")
await search_image(url, keyword, params, semaphore, page, black)
logger.warning(f'{data["pid"]} | {img_url} 已存在...')
# except Exception as e:
# logger.warning(f"PIX在线搜索图片错误,已再次调用 {type(e)}:{e}")
# await search_image(url, keyword, params, semaphore, page, black)
return pid_count, pic_count
@@ -206,7 +203,9 @@ async def get_image(img_url: str, user_id: int) -> Optional[str]:
params = {"id": pid}
for _ in range(3):
try:
response = await AsyncHttpx.get(f"{HIBIAPI}/api/pixiv/illust", params=params)
response = await AsyncHttpx.get(
f"{HIBIAPI}/api/pixiv/illust", params=params
)
if response.status_code == 200:
data = response.json()
if data.get("illust"):
@@ -215,22 +214,28 @@ async def get_image(img_url: str, user_id: int) -> Optional[str]:
"original_image_url"
]
else:
img_url = data["illust"]["meta_pages"][0][
"image_urls"
]["original"]
img_url = data["illust"]["meta_pages"][0]["image_urls"][
"original"
]
break
except TimeoutError:
pass
old_img_url = img_url
img_url = change_pixiv_image_links(
img_url, Config.get_config("pix", "PIX_IMAGE_SIZE"), Config.get_config("pixiv", "PIXIV_NGINX_URL")
img_url,
Config.get_config("pix", "PIX_IMAGE_SIZE"),
Config.get_config("pixiv", "PIXIV_NGINX_URL"),
)
old_img_url = change_pixiv_image_links(
old_img_url, None, Config.get_config("pixiv", "PIXIV_NGINX_URL")
)
for _ in range(3):
try:
response = await AsyncHttpx.get(img_url, headers=headers, timeout=Config.get_config("pix", "TIMEOUT"),)
response = await AsyncHttpx.get(
img_url,
headers=headers,
timeout=Config.get_config("pix", "TIMEOUT"),
)
if response.status_code == 404:
img_url = old_img_url
continue
@@ -238,7 +243,9 @@ async def get_image(img_url: str, user_id: int) -> Optional[str]:
TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg", "wb"
) as f:
await f.write(response.content)
change_img_md5(TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg")
change_img_md5(
TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg"
)
return TEMP_PATH / f"pix_{user_id}_{img_url.split('/')[-1][:-4]}.jpg"
except TimeoutError:
logger.warning(f"PIX:{img_url} 图片下载超时...")
@@ -264,7 +271,7 @@ async def uid_pid_exists(id_: str) -> bool:
return True
async def get_keyword_num(keyword: str) -> "int, int, int, int, int":
async def get_keyword_num(keyword: str) -> Tuple[int, int, int, int, int]:
"""
查看图片相关 tag 数量
:param keyword: 关键词tag
@@ -276,7 +283,7 @@ async def get_keyword_num(keyword: str) -> "int, int, int, int, int":
return count, r18_count, count_, setu_count, r18_count_
async def remove_image(pid: int, img_p: str) -> bool:
async def remove_image(pid: int, img_p: Optional[str]):
"""
删除置顶图片
:param pid: pid
@@ -285,7 +292,10 @@ async def remove_image(pid: int, img_p: str) -> bool:
if img_p:
if "p" not in img_p:
img_p = f"p{img_p}"
return await Pixiv.remove_image_data(pid, img_p)
if img_p:
await Pixiv.filter(pid=pid, img_p=img_p).delete()
else:
await Pixiv.filter(pid=pid).delete()
def gen_keyword_pic(
@@ -392,6 +402,3 @@ def _check_black(img_urls: List[str], black: List[str]) -> bool:
if b in img_url:
return False
return True
+60 -117
View File
@@ -1,79 +1,50 @@
from typing import Optional, List, Tuple
from services.db_context import db
from typing import List, Optional, Tuple
from tortoise import fields
from tortoise.contrib.postgres.functions import Random
from services.db_context import Model
class OmegaPixivIllusts(db.Model):
__tablename__ = "omega_pixiv_illusts"
__table_args__ = {'extend_existing': True}
class OmegaPixivIllusts(Model):
id = db.Column(db.Integer(), primary_key=True)
pid = db.Column(db.BigInteger(), nullable=False)
uid = db.Column(db.BigInteger(), nullable=False)
title = db.Column(db.String(), nullable=False)
uname = db.Column(db.String(), nullable=False)
classified = db.Column(db.Integer(), nullable=False)
nsfw_tag = db.Column(db.Integer(), nullable=False)
width = db.Column(db.Integer(), nullable=False)
height = db.Column(db.Integer(), nullable=False)
tags = db.Column(db.String(), nullable=False)
url = db.Column(db.String(), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
pid = fields.BigIntField()
"""pid"""
uid = fields.BigIntField()
"""uid"""
title = fields.CharField(255)
"""标题"""
uname = fields.CharField(255)
"""画师名称"""
classified = fields.IntField()
"""标记标签, 0=未标记, 1=已人工标记或从可信已标记来源获取"""
nsfw_tag = fields.IntField()
"""nsfw标签,-1=未标记, 0=safe, 1=setu. 2=r18"""
width = fields.IntField()
"""宽度"""
height = fields.IntField()
"""高度"""
tags = fields.TextField()
"""tags"""
url = fields.CharField(255)
"""pixiv url链接"""
_idx1 = db.Index("omega_pixiv_illusts_idx1", "pid", "url", unique=True)
@classmethod
async def add_image_data(
cls,
pid: int,
title: str,
width: int,
height: int,
url: str,
uid: int,
uname: str,
classified: int,
nsfw_tag: int,
tags: str,
):
"""
说明:
添加图片信息
参数:
:param pid: pid
:param title: 标题
:param width: 宽度
:param height: 长度
:param url: url链接
:param uid: 作者uid
:param uname: 作者名称
:param classified: 标记标签, 0=未标记, 1=已人工标记或从可信已标记来源获取
:param nsfw_tag: nsfw标签,-1=未标记, 0=safe, 1=setu. 2=r18
:param tags: 相关tag
"""
if not await cls.check_exists(pid):
await cls.create(
pid=pid,
title=title,
width=width,
height=height,
url=url,
uid=uid,
uname=uname,
classified=classified,
nsfw_tag=nsfw_tag,
tags=tags,
)
return True
return False
class Meta:
table = "omega_pixiv_illusts"
table_description = "omega图库数据表"
unique_together = ("pid", "url")
@classmethod
async def query_images(
cls,
keywords: Optional[List[str]] = None,
uid: Optional[int] = None,
pid: Optional[int] = None,
nsfw_tag: Optional[int] = 0,
num: int = 100
) -> List[Optional["OmegaPixivIllusts"]]:
cls,
keywords: Optional[List[str]] = None,
uid: Optional[int] = None,
pid: Optional[int] = None,
nsfw_tag: Optional[int] = 0,
num: int = 100,
) -> List["OmegaPixivIllusts"]:
"""
说明:
查找符合条件的图片
@@ -84,66 +55,38 @@ class OmegaPixivIllusts(db.Model):
:param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18
:param num: 获取图片数量
"""
if not num:
return []
query = cls
if nsfw_tag is not None:
query = cls.query.where(cls.nsfw_tag == nsfw_tag)
else:
query = cls.query
query = cls.filter(nsfw_tag=nsfw_tag)
if keywords:
for keyword in keywords:
query = query.where(cls.tags.contains(keyword))
query = query.filter(tags__contains=keyword)
elif uid:
query = query.where(cls.uid == uid)
query = query.filter(uid=uid)
elif pid:
query = query.where(cls.uid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
query = query.filter(pid=pid)
query = query.annotate(rand=Random()).limit(num)
return await query.all() # type: ignore
@classmethod
async def check_exists(cls, pid: int) -> bool:
"""
说明:
检测pid是否已存在
参数:
:param pid: 图片PID
"""
query = await cls.query.where(cls.pid == pid).gino.all()
return bool(query)
@classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> Tuple[int, int, int]:
async def get_keyword_num(
cls, tags: Optional[List[str]] = None
) -> Tuple[int, int, int]:
"""
说明:
获取相关关键词(keyword, tag)在图库中的数量
参数:
:param tags: 关键词/Tag
"""
setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count'))
query = cls.select('count')
query = cls
if tags:
for tag in tags:
query = query.where(cls.tags.contains(tag))
count = await query.where(cls.nsfw_tag == 0).gino.first()
setu_count = await query.where(cls.nsfw_tag == 1).gino.first()
r18_count = await query.where(cls.nsfw_tag == 2).gino.first()
return count[0], setu_count[0], r18_count[0]
@classmethod
async def get_all_pid(cls) -> List[int]:
"""
说明:
获取所有图片PID
"""
data = await cls.select('pid').gino.all()
return [x[0] for x in data]
# async def test(cls, nsfw_tag: int = 1):
# if nsfw_tag is not None:
# query = cls.query.where(cls.nsfw_tag == nsfw_tag)
# else:
# query = cls.query
# query = query.where((cls.width - cls.height) < 50)
# for x in await query.gino.all():
# print(x.pid)
query = query.filter(tags__contains=tag)
else:
query = query.all()
count = await query.filter(nsfw_tag=0).count()
setu_count = await query.filter(nsfw_tag=1).count()
r18_count = await query.filter(nsfw_tag=2).count()
return count, setu_count, r18_count
+55 -130
View File
@@ -1,105 +1,43 @@
from typing import Optional, List
from services.db_context import db
from typing import List, Optional, Tuple
from tortoise import fields
from tortoise.contrib.postgres.functions import Random
from services.db_context import Model
class Pixiv(db.Model):
__tablename__ = "pixiv"
__table_args__ = {'extend_existing': True}
class Pixiv(Model):
id = db.Column(db.Integer(), primary_key=True)
pid = db.Column(db.BigInteger(), nullable=False)
title = db.Column(db.String(), nullable=False)
width = db.Column(db.Integer(), nullable=False)
height = db.Column(db.Integer(), nullable=False)
view = db.Column(db.Integer(), nullable=False)
bookmarks = db.Column(db.Integer(), nullable=False)
img_url = db.Column(db.String(), nullable=False)
img_p = db.Column(db.String(), nullable=False)
uid = db.Column(db.BigInteger(), nullable=False)
author = db.Column(db.String(), nullable=False)
is_r18 = db.Column(db.Boolean(), nullable=False)
tags = db.Column(db.String(), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
pid = fields.BigIntField()
"""pid"""
uid = fields.BigIntField()
"""uid"""
author = fields.CharField(255)
"""作者"""
title = fields.CharField(255)
"""标题"""
width = fields.IntField()
"""宽度"""
height = fields.IntField()
"""高度"""
view = fields.IntField()
"""pixiv查看数"""
bookmarks = fields.IntField()
"""收藏数"""
tags = fields.TextField()
"""tags"""
img_url = fields.CharField(255)
"""pixiv url链接"""
img_p = fields.CharField(255)
"""图片pN"""
is_r18 = fields.BooleanField()
_idx1 = db.Index("pixiv_idx1", "pid", "img_url", unique=True)
@classmethod
async def add_image_data(
cls,
pid: int,
title: str,
width: int,
height: int,
view: int,
bookmarks: int,
img_url: str,
img_p: str,
uid: int,
author: str,
tags: str,
):
"""
说明:
添加图片信息
参数:
:param pid: pid
:param title: 标题
:param width: 宽度
:param height: 长度
:param view: 被查看次数
:param bookmarks: 收藏数
:param img_url: url链接
:param img_p: 张数
:param uid: 作者uid
:param author: 作者名称
:param tags: 相关tag
"""
if not await cls.check_exists(pid, img_p):
await cls.create(
pid=pid,
title=title,
width=width,
height=height,
view=view,
bookmarks=bookmarks,
img_url=img_url,
img_p=img_p,
uid=uid,
author=author,
is_r18=True if "R-18" in tags else False,
tags=tags,
)
return True
return False
@classmethod
async def remove_image_data(cls, pid: int, img_p: str) -> bool:
"""
说明:
删除图片数据
参数:
:param pid: 图片pid
:param img_p: 图片pid的张数,如:p0,p1
"""
try:
if img_p:
await cls.delete.where(
(cls.pid == pid) & (cls.img_p == img_p)
).gino.status()
else:
await cls.delete.where(cls.pid == pid).gino.status()
return True
except Exception:
return False
@classmethod
async def get_all_pid(cls) -> List[int]:
"""
说明:
获取所有PID
"""
query = await cls.query.select("pid").gino.first()
pid = [x[0] for x in query]
return list(set(pid))
class Meta:
table = "pixiv"
table_description = "pix图库数据表"
unique_together = ("pid", "img_url", "img_p")
# 0:非r18 1:r18 2:混合
@classmethod
@@ -109,7 +47,7 @@ class Pixiv(db.Model):
uid: Optional[int] = None,
pid: Optional[int] = None,
r18: Optional[int] = 0,
num: int = 100
num: int = 100,
) -> List[Optional["Pixiv"]]:
"""
说明:
@@ -121,50 +59,37 @@ class Pixiv(db.Model):
:param r18: 是否r18,0:非r18 1:r18 2:混合
:param num: 查找图片的数量
"""
if not num:
return []
query = cls
if r18 == 0:
query = cls.query.where(cls.is_r18 == False)
query = query.filter(is_r18=False)
elif r18 == 1:
query = cls.query.where(cls.is_r18 == True)
else:
query = cls.query
query = query.filter(is_r18=True)
if keywords:
for keyword in keywords:
query = query.where(cls.tags.contains(keyword))
query = query.filter(tags__contains=keyword)
elif uid:
query = query.where(cls.uid == uid)
query = query.filter(uid=uid)
elif pid:
query = query.where(cls.pid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
query = query.filter(pid=pid)
query = query.annotate(rand=Random()).limit(num)
return await query.all() # type: ignore
@classmethod
async def check_exists(cls, pid: int, img_p: str) -> bool:
"""
说明:
检测pid是否已存在
参数:
:param pid: 图片PID
:param img_p: 张数
"""
query = await cls.query.where(
(cls.pid == pid) & (cls.img_p == img_p)
).gino.all()
return bool(query)
@classmethod
async def get_keyword_num(cls, tags: List[str] = None) -> "int, int":
async def get_keyword_num(cls, tags: Optional[List[str]] = None) -> Tuple[int, int]:
"""
说明:
获取相关关键词(keyword, tag)在图库中的数量
参数:
:param tags: 关键词/Tag
"""
setattr(Pixiv, 'count', db.func.count(cls.pid).label('count'))
query = cls.select('count')
query = cls
if tags:
for tag in tags:
query = query.where(cls.tags.contains(tag))
count = await query.where(cls.is_r18 == False).gino.first()
r18_count = await query.where(cls.is_r18 == True).gino.first()
return count[0], r18_count[0]
query = query.filter(tags__contains=tag)
else:
query = query.all()
count = await query.filter(is_r18=False).count()
r18_count = await query.filter(is_r18=True).count()
return count, r18_count
+30 -103
View File
@@ -1,101 +1,42 @@
from services.db_context import db
from typing import Set, List
from typing import List, Set, Tuple
from tortoise import fields
from services.db_context import Model
class PixivKeywordUser(db.Model):
class PixivKeywordUser(Model):
__tablename__ = "pixiv_keyword_users"
__table_args__ = {'extend_existing': True}
__table_args__ = {"extend_existing": True}
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
keyword = db.Column(db.String(), nullable=False)
is_pass = db.Column(db.Boolean(), default=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
keyword = fields.CharField(255, unique=True)
"""关键词"""
is_pass = fields.BooleanField()
"""是否通过"""
_idx1 = db.Index("pixiv_keyword_users_idx1", "keyword", unique=True)
class Meta:
table = "pixiv_keyword_users"
table_description = "pixiv关键词数据表"
@classmethod
async def add_keyword(
cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str]
) -> bool:
"""
说明:
添加搜图的关键词
参数:
:param user_qq: qq号
:param group_id: 群号
:param keyword: 关键词
:param superusers: 是否为超级用户
"""
is_pass = True if str(user_qq) in superusers else False
if not await cls._check_keyword_exists(keyword):
await cls.create(
user_qq=user_qq, group_id=group_id, keyword=keyword, is_pass=is_pass
)
return True
return False
@classmethod
async def delete_keyword(cls, keyword: str) -> bool:
"""
说明:
删除关键词
参数:
:param keyword: 关键词
"""
if await cls._check_keyword_exists(keyword):
query = cls.query.where(cls.keyword == keyword).with_for_update()
query = await query.gino.first()
await query.delete()
return True
return False
@classmethod
async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int":
"""
说明:
通过或禁用关键词
参数:
:param keyword: 关键词
:param is_pass: 通过状态
"""
if await cls._check_keyword_exists(keyword):
query = cls.query.where(cls.keyword == keyword).with_for_update()
query = await query.gino.first()
await query.update(
is_pass=is_pass,
).apply()
return query.user_qq, query.group_id
return 0, 0
@classmethod
async def get_all_user_dict(cls) -> dict:
"""
说明:
获取关键词数据库各个用户贡献的关键词字典
"""
tmp = {}
query = await cls.query.gino.all()
for user in query:
if not tmp.get(user.user_qq):
tmp[user.user_qq] = {"keyword": []}
tmp[user.user_qq]["keyword"].append(user.keyword)
return tmp
@classmethod
async def get_current_keyword(cls) -> "List[str], List[str]":
async def get_current_keyword(cls) -> Tuple[List[str], List[str]]:
"""
说明:
获取当前通过与未通过的关键词
"""
pass_keyword = []
not_pass_keyword = []
query = await cls.query.gino.all()
for user in query:
if user.is_pass:
pass_keyword.append(user.keyword)
for data in await cls.all().values_list("keyword", "is_pass"):
if data[1]:
pass_keyword.append(data[0])
else:
not_pass_keyword.append(user.keyword)
not_pass_keyword.append(data[0])
return pass_keyword, not_pass_keyword
@classmethod
@@ -105,23 +46,9 @@ class PixivKeywordUser(db.Model):
获取黑名单PID
"""
black_pid = []
query = await cls.query.where(cls.user_qq == 114514).gino.all()
for image in query:
black_pid.append(image.keyword[6:])
keyword_list = await cls.filter(user_qq=114514).values_list(
"keyword", flat=True
)
for image in keyword_list:
black_pid.append(image[6:])
return black_pid
@classmethod
async def _check_keyword_exists(cls, keyword: str) -> bool:
"""
说明:
检测关键词是否已存在
参数:
:param keyword: 关键词
"""
current_keyword = []
query = await cls.query.gino.all()
for user in query:
current_keyword.append(user.keyword)
if keyword in current_keyword:
return True
return False
+52 -21
View File
@@ -1,14 +1,17 @@
from nonebot import on_command
from utils.utils import is_number
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from nonebot.params import CommandArg, Command
from typing import Tuple
from ._data_source import uid_pid_exists
from ._model.pixiv_keyword_user import PixivKeywordUser
from ._model.pixiv import Pixiv
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.utils import is_number
from ._data_source import uid_pid_exists
from ._model.pixiv import Pixiv
from ._model.pixiv_keyword_user import PixivKeywordUser
__zx_plugin_name__ = "PIX关键词/UID/PID添加管理 [Superuser]"
__plugin_usage__ = """
usage:
@@ -46,9 +49,16 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
if msg:
if await PixivKeywordUser.add_keyword(
event.user_id, group_id, msg, bot.config.superusers
):
# if await PixivKeywordUser.add_keyword(
# event.user_id, group_id, msg, bot.config.superusers
# ):
if not await PixivKeywordUser.exists(keyword=msg):
await PixivKeywordUser.create(
user_qq=event.user_id,
group_id=group_id,
keyword=msg,
is_pass=str(event.user_id) in bot.config.superusers,
)
await add_keyword.send(
f"已成功添加pixiv搜图关键词:{msg},请等待管理员通过该关键词!", at_sender=True
)
@@ -63,7 +73,12 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
@add_uid_pid.handle()
async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
async def _(
bot: Bot,
event: MessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
msg = arg.extract_plain_text().strip()
exists_flag = True
if msg.find("-f") != -1 and str(event.user_id) in bot.config.superusers:
@@ -77,16 +92,23 @@ async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg
msg = f"uid:{msg}"
else:
msg = f"pid:{msg}"
if await Pixiv.check_exists(int(msg[4:]), "p0"):
if await Pixiv.get_or_none(pid=int(msg[4:]), img_p="p0"):
await add_uid_pid.finish(f"该PID:{msg[4:]}已存在...", at_sender=True)
if not await uid_pid_exists(msg) and exists_flag:
await add_uid_pid.finish("画师或作品不存在或搜索正在CD,请稍等...", at_sender=True)
group_id = -1
if isinstance(event, GroupMessageEvent):
group_id = event.group_id
if await PixivKeywordUser.add_keyword(
event.user_id, group_id, msg, bot.config.superusers
):
# if await PixivKeywordUser.add_keyword(
# event.user_id, group_id, msg, bot.config.superusers
# ):
if not await PixivKeywordUser.exists(keyword=msg):
await PixivKeywordUser.create(
user_qq=event.user_id,
group_id=group_id,
keyword=msg,
is_pass=str(event.user_id) in bot.config.superusers,
)
await add_uid_pid.send(
f"已成功添加pixiv搜图UID/PID:{msg[4:]},请等待管理员通过!", at_sender=True
)
@@ -106,12 +128,21 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
pid = pid[: pid.find("p")]
if not is_number(pid):
await add_black_pid.finish("PID必须全部是数字!", at_sender=True)
if await PixivKeywordUser.add_keyword(
114514,
114514,
f"black:{pid}{f'_p{img_p}' if img_p else ''}",
bot.config.superusers,
# if await PixivKeywordUser.add_keyword(
# 114514,
# 114514,
# f"black:{pid}{f'_p{img_p}' if img_p else ''}",
# bot.config.superusers,
# ):
if not await PixivKeywordUser.exists(
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}"
):
await PixivKeywordUser.create(
user_qq=114514,
group_id=114514,
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}",
is_pass=str(event.user_id) in bot.config.superusers,
)
await add_black_pid.send(f"已添加PID:{pid} 至黑名单中...")
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+46 -23
View File
@@ -1,15 +1,17 @@
from nonebot import on_command
from utils.utils import is_number
from utils.message_builder import at
from services.log import logger
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message
from nonebot.params import CommandArg, Command
from nonebot.permission import SUPERUSER
from ._data_source import remove_image
from ._model.pixiv_keyword_user import PixivKeywordUser
from ._model.pixiv import Pixiv
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import Command, CommandArg
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.message_builder import at
from utils.utils import is_number
from ._data_source import remove_image
from ._model.pixiv import Pixiv
from ._model.pixiv_keyword_user import PixivKeywordUser
__zx_plugin_name__ = "PIX关键词/UID/PID删除管理 [Superuser]"
__plugin_usage__ = """
@@ -60,7 +62,8 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
msg = f"uid:{msg}"
if msg.lower().startswith("pid"):
msg = "pid:" + msg.replace("pid", "").replace(":", "")
if await PixivKeywordUser.delete_keyword(msg):
if data := await PixivKeywordUser.get_or_none(keyword=msg):
await data.delete()
await del_keyword.send(f"删除搜图关键词/UID:{msg} 成功...")
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
@@ -97,22 +100,31 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
if await remove_image(int(pid), img_p):
msg += f'{pid}{f"_p{img_p}" if img_p else ""},'
if flag:
if await PixivKeywordUser.add_keyword(
114514,
114514,
f"black:{pid}{f'_p{img_p}' if img_p else ''}",
bot.config.superusers,
# if await PixivKeywordUser.add_keyword(
# 114514,
# 114514,
# f"black:{pid}{f'_p{img_p}' if img_p else ''}",
# bot.config.superusers,
# ):
if await PixivKeywordUser.exists(
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}"
):
await PixivKeywordUser.create(
user_qq=114514,
group_id=114514,
keyword=f"black:{pid}{f'_p{img_p}' if img_p else ''}",
is_pass=False,
)
black_pid += f'{pid}{f"_p{img_p}" if img_p else ""},'
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除了PIX图片 PID:{pid}{f'_p{img_p}' if img_p else ''}"
)
else:
await del_pic.send(
f"PIX:删除pid:{pid}{f'_p{img_p}' if img_p else ''} 失败.."
)
# else:
# await del_pic.send(
# f"PIX:删除pid:{pid}{f'_p{img_p}' if img_p else ''} 失败.."
# )
else:
await del_pic.send(
f"PIX:图片pix:{pid}{f'_p{img_p}' if img_p else ''} 不存在...无法删除.."
@@ -127,7 +139,12 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
@pass_keyword.handle()
async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
async def _(
bot: Bot,
event: MessageEvent,
cmd: Tuple[str, ...] = Command(),
arg: Message = CommandArg(),
):
tmp = {"group": {}, "private": {}}
msg = arg.extract_plain_text().strip()
if not msg:
@@ -145,7 +162,13 @@ async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg
if not is_number(x[4:]):
await pass_keyword.send(f"UID/PID:{x} 非全数字,跳过该关键词...")
continue
user_id, group_id = await PixivKeywordUser.set_keyword_pass(x, flag)
data = await PixivKeywordUser.get_or_none(keyword=x)
user_id = 0
group_id = 0
if data:
data.is_pass = flag
await data.save(update_fields=["is_pass"])
user_id, group_id = data.user_qq, data.group_id
if not user_id:
await pass_keyword.send(f"未找到关键词/UID:{x},请检查关键词/UID是否存在...")
continue
@@ -163,7 +186,7 @@ async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg
else:
tmp["group"][group_id][user_id]["keyword"].append(x)
msg = " ".join(msg)
await pass_keyword.send(f'已成功{cmd[0][:2]}搜图关键词:{msg}....')
await pass_keyword.send(f"已成功{cmd[0][:2]}搜图关键词:{msg}....")
for user in tmp["private"]:
x = ",".join(tmp["private"][user]["keyword"])
await bot.send_private_msg(
+13 -11
View File
@@ -1,11 +1,13 @@
from nonebot import on_command
from utils.message_builder import image
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message
from ._data_source import gen_keyword_pic, get_keyword_num
from ._model.pixiv_keyword_user import PixivKeywordUser
from nonebot.params import CommandArg
import asyncio
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
from nonebot.params import CommandArg
from utils.message_builder import image
from ._data_source import gen_keyword_pic, get_keyword_num
from ._model.pixiv_keyword_user import PixivKeywordUser
__zx_plugin_name__ = "查看pix图库"
__plugin_usage__ = """
@@ -35,12 +37,12 @@ show_pix = on_command("查看pix图库", priority=1, block=True)
@my_keyword.handle()
async def _(event: MessageEvent):
data = await PixivKeywordUser.get_all_user_dict()
if data.get(event.user_id) is None or not data[event.user_id]["keyword"]:
await my_keyword.finish("您目前没有提供任何Pixiv搜图关键字...", at_sender=True)
await my_keyword.send(
f"您目前提供的如下关键字:\n\t" + ",".join(data[event.user_id]["keyword"])
data = await PixivKeywordUser.filter(user_qq=event.user_id).values_list(
"keyword", flat=True
)
if not data:
await my_keyword.finish("您目前没有提供任何Pixiv搜图关键字...", at_sender=True)
await my_keyword.send(f"您目前提供的如下关键字:\n\t" + ",".join(data))
@show_keyword.handle()
+34 -31
View File
@@ -1,21 +1,22 @@
import re
from nonebot import on_command
from utils.utils import is_number
from nonebot.permission import SUPERUSER
from ._data_source import start_update_image_url
from ._model.pixiv_keyword_user import PixivKeywordUser
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
from ._model.pixiv import Pixiv
from nonebot.adapters.onebot.v11 import Message
from nonebot.params import CommandArg
import time
from services.log import logger
from pathlib import Path
from typing import List
import asyncio
import os
import re
import time
from pathlib import Path
from typing import List
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Message
from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER
from services.log import logger
from utils.utils import is_number
from ._data_source import start_update_image_url
from ._model.omega_pixiv_illusts import OmegaPixivIllusts
from ._model.pixiv import Pixiv
from ._model.pixiv_keyword_user import PixivKeywordUser
__zx_plugin_name__ = "pix检查更新 [Superuser]"
__plugin_usage__ = """
@@ -146,11 +147,11 @@ async def _(arg: Message = CommandArg()):
async def _():
async def _tasks(line: str, all_pid: List[int], length: int, index: int):
data = line.split("VALUES", maxsplit=1)[-1].strip()[1:-2]
num_list = re.findall(r'(\d+)', data)
num_list = re.findall(r"(\d+)", data)
pid = int(num_list[1])
uid = int(num_list[2])
id_ = 3
while num_list[id_] not in ['0', '1']:
while num_list[id_] not in ["0", "1"]:
id_ += 1
classified = int(num_list[id_])
nsfw_tag = int(num_list[id_ + 1])
@@ -164,23 +165,25 @@ async def _():
if pid in all_pid:
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
return
if await OmegaPixivIllusts.add_image_data(
pid=pid,
title=title,
width=width,
height=height,
url=url,
uid=uid,
nsfw_tag=nsfw_tag,
tags=tags,
uname=uname,
classified=classified
):
_, is_create = await OmegaPixivIllusts.get_or_create(
pid=pid,
title=title,
width=width,
height=height,
url=url,
uid=uid,
nsfw_tag=nsfw_tag,
tags=tags,
uname=uname,
classified=classified,
)
if is_create:
logger.info(
f"成功添加OmegaPixivIllusts图库数据 pid:{pid} 本次预计存储 {length} 张,已更新第 {index} 张"
)
else:
logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
omega_pixiv_illusts = None
for file in os.listdir("."):
if "omega_pixiv_artwork" in file and ".sql" in file:
@@ -190,13 +193,13 @@ async def _():
lines = f.readlines()
tasks = []
length = len([x for x in lines if "INSERT INTO" in x.upper()])
all_pid = await OmegaPixivIllusts.get_all_pid()
all_pid = await OmegaPixivIllusts.all().values_list("pid", flat=True)
index = 0
logger.info("检测到OmegaPixivIllusts数据库,准备开始更新....")
for line in lines:
if "INSERT INTO" in line.upper():
index += 1
logger.info(f'line: {line} 加入更新计划')
logger.info(f"line: {line} 加入更新计划")
tasks.append(
asyncio.ensure_future(_tasks(line, all_pid, length, index))
)
+14 -13
View File
@@ -1,13 +1,14 @@
from configs.path_config import IMAGE_PATH
import platform
from asyncio.exceptions import TimeoutError
from pathlib import Path
from typing import Optional
from configs.config import Config
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.message_builder import image
from utils.utils import change_img_md5
from asyncio.exceptions import TimeoutError
from configs.config import Config
from utils.http_utils import AsyncHttpx
from typing import Optional
from services.log import logger
from pathlib import Path
import platform
# if platform.system() == "Windows":
# import asyncio
@@ -133,9 +134,9 @@ async def download_pixiv_imgs(
)
try:
file = (
f"{IMAGE_PATH}/temp/{user_id}_{forward_msg_index}_{index}_pixiv.jpg"
TEMP_PATH / f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg"
if forward_msg_index is not None
else f"{IMAGE_PATH}/temp/{user_id}_{index}_pixiv.jpg"
else TEMP_PATH / f"{user_id}_{index}_pixiv.jpg"
)
file = Path(file)
try:
@@ -147,11 +148,11 @@ async def download_pixiv_imgs(
change_img_md5(file)
if forward_msg_index is not None:
result += image(
f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg",
"temp",
TEMP_PATH
/ f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg",
)
else:
result += image(f"{user_id}_{index}_pixiv.jpg", "temp")
result += image(TEMP_PATH / f"{user_id}_{index}_pixiv.jpg")
index += 1
except OSError:
if file.exists():
+15 -9
View File
@@ -1,12 +1,14 @@
import os
import random
from nonebot import on_notice
from nonebot.adapters.onebot.v11 import PokeNotifyEvent
from configs.path_config import RECORD_PATH, IMAGE_PATH
from utils.message_builder import record, image, poke
from services.log import logger
import random
from utils.utils import CountLimiter
from configs.path_config import IMAGE_PATH, RECORD_PATH
from models.ban_user import BanUser
import os
from services.log import logger
from utils.message_builder import image, poke, record
from utils.utils import CountLimiter
__zx_plugin_name__ = "戳一戳"
@@ -64,13 +66,17 @@ async def _poke_event(event: PokeNotifyEvent):
rand = random.random()
path = random.choice(["luoli", "meitu"])
if rand <= 0.3 and len(os.listdir(IMAGE_PATH / "image_management" / path)) > 0:
index = random.randint(0, len(os.listdir(IMAGE_PATH / "image_management" / path)) - 1)
result = f"id:{index}" + image(f"{index}.jpg", "image_management/" + path)
index = random.randint(
0, len(os.listdir(IMAGE_PATH / "image_management" / path)) - 1
)
result = f"id:{index}" + image(
IMAGE_PATH / "image_management" / path / f"{index}.jpg"
)
await poke_.send(result)
logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} {result}")
elif 0.3 < rand < 0.6:
voice = random.choice(os.listdir(RECORD_PATH / "dinggong"))
result = record(voice, "dinggong")
result = record(RECORD_PATH / "dinggong" / voice)
await poke_.send(result)
await poke_.send(voice.split("_")[1])
logger.info(
+30 -20
View File
@@ -1,20 +1,22 @@
import asyncio
import random
import time
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GROUP, Bot, GroupMessageEvent, Message
from nonebot.params import ArgStr, Command, CommandArg
from nonebot.typing import T_State
from utils.utils import is_number, get_message_at
from nonebot.params import CommandArg, Command, ArgStr
from models.group_member_info import GroupInfoUser
from utils.message_builder import at, image
from .model import RussianUser
from models.bag_user import BagUser
from services.log import logger
from .data_source import rank
from configs.config import NICKNAME, Config
from typing import Tuple
import random
import asyncio
import time
from configs.config import NICKNAME, Config
from models.bag_user import BagUser
from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.message_builder import at, image
from utils.utils import get_message_at, is_number
from .data_source import rank
from .model import RussianUser
__zx_plugin_name__ = "俄罗斯轮盘"
__plugin_usage__ = """
@@ -156,7 +158,9 @@ async def _(event: GroupMessageEvent):
await accept.finish("又不是找你决斗,你拒绝什么啊!气!", at_sender=True)
if rs_player[event.group_id]["at"] == event.user_id:
at_player_name = (
await GroupInfoUser.get_member_info(event.user_id, event.group_id)
await GroupInfoUser.get_or_none(
user_qq=event.user_id, group_id=event.group_id
)
).user_name
await accept.send(
Message(f"{at(rs_player[event.group_id][1])}\n" f"{at_player_name}拒绝了你的对决!")
@@ -291,7 +295,7 @@ async def _(
at_ = at_[0]
try:
at_player_name = (
await GroupInfoUser.get_member_info(at_, event.group_id)
await GroupInfoUser.get_or_none(user_qq=at_, group_id=event.group_id)
).user_name
except AttributeError:
at_player_name = at(at_)
@@ -359,14 +363,14 @@ async def _(bot: Bot, event: GroupMessageEvent):
[
f"不要打扰 {player1_name} 和 {player2_name} 的决斗啊!",
f"给我好好做好一个观众!不然{NICKNAME}就要生气了",
f"不要捣乱啊baka{(await GroupInfoUser.get_member_info(event.user_id, event.group_id)).user_name}!",
f"不要捣乱啊baka{(await GroupInfoUser.get_or_none(user_qq=event.user_id, group_id=event.group_id)).user_name}!",
]
),
at_sender=True,
)
await shot.finish(
f"你的左轮不是连发的!该 "
f'{(await GroupInfoUser.get_member_info(int(rs_player[event.group_id]["next"]), event.group_id)).user_name} 开枪了'
f'{(await GroupInfoUser.get_or_none(user_qq=int(rs_player[event.group_id]["next"]), group_id=event.group_id)).user_name} 开枪了'
)
if rs_player[event.group_id]["bullet"][rs_player[event.group_id]["index"]] != 1:
await shot.send(
@@ -440,8 +444,12 @@ async def end_game(bot: Bot, event: GroupMessageEvent):
await RussianUser.money(lose_user_id, event.group_id, "lose", money)
await BagUser.add_gold(win_user_id, event.group_id, money - fee)
await BagUser.spend_gold(lose_user_id, event.group_id, money)
win_user = await RussianUser.ensure(win_user_id, event.group_id)
lose_user = await RussianUser.ensure(lose_user_id, event.group_id)
win_user, _ = await RussianUser.get_or_create(
user_qq=win_user_id, group_id=event.group_id
)
lose_user, _ = await RussianUser.get_or_create(
user_qq=lose_user_id, group_id=event.group_id
)
bullet_str = ""
for x in rs_player[event.group_id]["bullet"]:
bullet_str += "__ " if x == 0 else "| "
@@ -467,7 +475,9 @@ async def end_game(bot: Bot, event: GroupMessageEvent):
@record.handle()
async def _(event: GroupMessageEvent):
user = await RussianUser.ensure(event.user_id, event.group_id)
user, _ = await RussianUser.get_or_create(
user_qq=event.user_id, group_id=event.group_id
)
await record.send(
f"俄罗斯轮盘\n"
f"总胜利场次:{user.win_count}\n"
+15 -24
View File
@@ -1,42 +1,33 @@
from .model import RussianUser
from typing import Optional
from utils.data_utils import init_rank
from utils.image_utils import BuildMat
from .model import RussianUser
async def rank(group_id: int, itype: str, num: int) -> Optional[BuildMat]:
all_users = await RussianUser.get_all_user(group_id)
all_users = await RussianUser.filter(group_id=group_id).all()
all_user_id = [user.user_qq for user in all_users]
if itype == 'win_rank':
rank_name = '胜场排行榜'
if itype == "win_rank":
rank_name = "胜场排行榜"
all_user_data = [user.win_count for user in all_users]
elif itype == 'lose_rank':
rank_name = '败场排行榜'
elif itype == "lose_rank":
rank_name = "败场排行榜"
all_user_data = [user.fail_count for user in all_users]
elif itype == 'make_money':
rank_name = '赢取金币排行榜'
elif itype == "make_money":
rank_name = "赢取金币排行榜"
all_user_data = [user.make_money for user in all_users]
elif itype == 'spend_money':
rank_name = '输掉金币排行榜'
elif itype == "spend_money":
rank_name = "输掉金币排行榜"
all_user_data = [user.lose_money for user in all_users]
elif itype == 'max_winning_streak':
rank_name = '最高连胜排行榜'
elif itype == "max_winning_streak":
rank_name = "最高连胜排行榜"
all_user_data = [user.max_winning_streak for user in all_users]
else:
rank_name = '最高连败排行榜'
rank_name = "最高连败排行榜"
all_user_data = [user.max_losing_streak for user in all_users]
rst = None
if all_users:
rst = await init_rank(rank_name, all_user_id, all_user_data, group_id, num)
return rst
+74 -102
View File
@@ -1,43 +1,41 @@
from services.db_context import db
from typing import List
from tortoise import fields
from services.db_context import Model
class RussianUser(db.Model):
__tablename__ = "russian_users"
__table_args__ = {'extend_existing': True}
class RussianUser(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger(), nullable=False)
win_count = db.Column(db.Integer(), default=0)
fail_count = db.Column(db.Integer(), default=0)
make_money = db.Column(db.Integer(), default=0)
lose_money = db.Column(db.Integer(), default=0)
winning_streak = db.Column(db.Integer(), default=0)
losing_streak = db.Column(db.Integer(), default=0)
max_winning_streak = db.Column(db.Integer(), default=0)
max_losing_streak = db.Column(db.Integer(), default=0)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField()
"""群聊id"""
win_count = fields.IntField(default=0)
"""胜利次数"""
fail_count = fields.IntField(default=0)
"""失败次数"""
make_money = fields.IntField(default=0)
"""赢得金币"""
lose_money = fields.IntField(default=0)
"""输得金币"""
winning_streak = fields.IntField(default=0)
"""当前连胜"""
losing_streak = fields.IntField(default=0)
"""当前连败"""
max_winning_streak = fields.IntField(default=0)
"""最大连胜"""
max_losing_streak = fields.IntField(default=0)
"""最大连败"""
_idx1 = db.Index("russian_group_users_idx1", "user_qq", "group_id", unique=True)
class Meta:
table = "russian_users"
table_description = "俄罗斯轮盘数据表"
unique_together = ("user_qq", "group_id")
@classmethod
async def ensure(cls, user_qq: int, group_id: int) -> "RussianUser":
"""
说明:
获取用户对象
参数:
:param user_qq: qq号
:param group_id: 群号
"""
user = (
await cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
.with_for_update()
.gino.first()
)
return user or await cls.create(user_qq=user_qq, group_id=group_id)
@classmethod
async def add_count(cls, user_qq: int, group_id: int, itype: str) -> bool:
async def add_count(cls, user_qq: int, group_id: int, itype: str):
"""
说明:
添加用户输赢次数
@@ -46,43 +44,43 @@ class RussianUser(db.Model):
:param group_id: 群号
:param itype: 输或赢 'win' or 'lose'
"""
try:
user = (
await cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
.with_for_update()
.gino.first()
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
if itype == "win":
_max = (
user.max_winning_streak
if user.max_winning_streak > user.winning_streak + 1
else user.winning_streak + 1
)
user.win_count = user.win_count + 1
user.winning_streak = user.winning_streak + 1
user.losing_streak = 0
user.max_winning_streak = _max
await user.save(
update_fields=[
"win_count",
"winning_streak",
"losing_streak",
"max_winning_streak",
]
)
elif itype == "lose":
_max = (
user.max_losing_streak
if user.max_losing_streak > user.losing_streak + 1
else user.losing_streak + 1
)
user.fail_count = user.fail_count + 1
user.losing_streak = user.losing_streak + 1
user.winning_streak = 0
user.max_losing_streak = _max
await user.save(
update_fields=[
"fail_count",
"winning_streak",
"losing_streak",
"max_losing_streak",
]
)
if not user:
user = await cls.create(user_qq=user_qq, group_id=group_id)
if itype == "win":
_max = (
user.max_winning_streak
if user.max_winning_streak > user.winning_streak + 1
else user.winning_streak + 1
)
await user.update(
win_count=user.win_count + 1,
winning_streak=user.winning_streak + 1,
losing_streak=0,
max_winning_streak=_max
).apply()
elif itype == "lose":
_max = (
user.max_losing_streak
if user.max_losing_streak > user.losing_streak + 1
else user.losing_streak + 1
)
await user.update(
fail_count=user.fail_count + 1,
losing_streak=user.losing_streak + 1,
winning_streak=0,
max_losing_streak=_max,
).apply()
return True
except Exception:
return False
@classmethod
async def money(cls, user_qq: int, group_id: int, itype: str, count: int) -> bool:
@@ -95,35 +93,9 @@ class RussianUser(db.Model):
:param itype: 输或赢 'win' or 'lose'
:param count: 金钱数量
"""
try:
user = (
await cls.query.where(
(cls.user_qq == user_qq) & (cls.group_id == group_id)
)
.with_for_update()
.gino.first()
)
if not user:
user = await cls.create(user_qq=user_qq, group_id=group_id)
if itype == "win":
await user.update(
make_money=user.make_money + count,
).apply()
elif itype == "lose":
await user.update(
lose_money=user.lose_money + count,
).apply()
return True
except Exception:
return False
@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()
return users
user, _ = await cls.get_or_create(user_qq=user_qq, group_id=group_id)
if itype == "win":
user.make_money = user.make_money + count
elif itype == "lose":
user.lose_money = user.lose_money + count
await user.save(update_fields=["make_money", "lose_money"])
+12 -11
View File
@@ -1,12 +1,14 @@
import os
import random
from nonebot import on_keyword
from utils.message_builder import record
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
from nonebot.rule import to_me
from nonebot.typing import T_State
from configs.path_config import RECORD_PATH
from services.log import logger
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent
from nonebot.rule import to_me
import random
import os
from utils.message_builder import record
__zx_plugin_name__ = "骂我"
__plugin_usage__ = """
@@ -25,10 +27,7 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["骂老子", "骂我"],
}
__plugin_cd_limit__ = {
"cd": 3,
"rst": "就...就算求我骂你也得慢慢来..."
}
__plugin_cd_limit__ = {"cd": 3, "rst": "就...就算求我骂你也得慢慢来..."}
dg_voice = on_keyword({"骂"}, rule=to_me(), priority=5, block=True)
@@ -38,7 +37,9 @@ dg_voice = on_keyword({"骂"}, rule=to_me(), priority=5, block=True)
async def _(bot: Bot, event: MessageEvent, state: T_State):
if len(str((event.get_message()))) > 1:
voice = random.choice(os.listdir(RECORD_PATH / "dinggong"))
result = record(voice, "dinggong")
result = record(
RECORD_PATH / "dinggong" / voice,
)
await dg_voice.send(result)
await dg_voice.send(voice.split("_")[1])
logger.info(
+48 -161
View File
@@ -1,64 +1,44 @@
from services.db_context import db
from typing import List, Optional
from tortoise import fields
from tortoise.contrib.postgres.functions import Random
from tortoise.expressions import Q
class Setu(db.Model):
__tablename__ = "setu"
__table_args__ = {'extend_existing': True}
from services.db_context import Model
id = db.Column(db.Integer(), primary_key=True)
local_id = db.Column(db.Integer(), nullable=False)
title = db.Column(db.String(), nullable=False)
author = db.Column(db.String(), nullable=False)
pid = db.Column(db.BigInteger(), nullable=False)
img_hash = db.Column(db.String(), nullable=False)
img_url = db.Column(db.String(), nullable=False)
is_r18 = db.Column(db.Boolean(), nullable=False)
tags = db.Column(db.String())
_idx1 = db.Index("setu_pid_img_url_idx1", "pid", "img_url", unique=True)
class Setu(Model):
@classmethod
async def add_setu_data(
cls,
local_id: int,
title: str,
author: str,
pid: int,
img_hash: str,
img_url: str,
tags: str,
):
"""
说明:
添加一份色图数据
参数:
:param local_id: 本地存储id
:param title: 标题
:param author: 作者
:param pid: 图片pid
:param img_hash: 图片hash值
:param img_url: 图片链接
:param tags: 图片标签
"""
if not await cls._check_exists(pid, img_url):
await cls.create(
local_id=local_id,
title=title,
author=author,
pid=pid,
img_hash=img_hash,
img_url=img_url,
is_r18=True if "R-18" in tags else False,
tags=tags,
)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
local_id = fields.IntField()
"""本地存储下标"""
title = fields.CharField(255)
"""标题"""
author = fields.CharField(255)
"""作者"""
pid = fields.BigIntField()
"""pid"""
img_hash = fields.TextField()
"""图片hash"""
img_url = fields.CharField(255)
"""pixiv url链接"""
is_r18 = fields.BooleanField()
"""是否r18"""
tags = fields.TextField()
"""tags"""
class Meta:
table = "setu"
table_description = "色图数据表"
unique_together = ("pid", "img_url")
@classmethod
async def query_image(
cls,
local_id: Optional[int] = None,
tags: Optional[List[str]] = None,
r18: int = 0,
r18: bool = False,
limit: int = 50,
):
"""
@@ -71,58 +51,17 @@ class Setu(db.Model):
:param limit: 获取数量
"""
if local_id:
flag = True if r18 == 1 else False
return await cls.query.where(
(cls.local_id == local_id) & (cls.is_r18 == flag)
).gino.first()
if r18 == 0:
query = cls.query.where(cls.is_r18 == False)
elif r18 == 1:
query = cls.query.where(cls.is_r18 == True)
else:
query = cls.query
return await cls.filter(is_r18=r18, local_id=local_id).first()
query = cls.filter(is_r18=r18)
if tags:
for tag in tags:
query = query.where(cls.tags.contains(tag) | cls.title.contains(tag) | cls.author.contains(tag))
query = query.order_by(db.func.random()).limit(limit)
return await query.gino.all()
@classmethod
async def get_image_count(cls, r18: int = 0) -> int:
"""
说明:
查询图片数量
"""
flag = False if r18 == 0 else True
setattr(Setu, 'count', db.func.count(cls.local_id).label('count'))
count = await cls.select('count').where(cls.is_r18 == flag).gino.first()
return count[0]
@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()
return query
@classmethod
async def _check_exists(cls, pid: int, img_url: str) -> bool:
"""
说明:
检测图片是否存在
参数:
:param pid: 图片pid
:param img_url: 图片链接
"""
return bool(
await cls.query.where(
(cls.pid == pid) & (cls.img_url == img_url)
).gino.first()
)
query = query.filter(
Q(tags__contains=tag)
| Q(title__contains=tag)
| Q(author__contains=tag)
)
query = query.annotate(rand=Random()).limit(limit)
return await query.all()
@classmethod
async def delete_image(cls, pid: int) -> int:
@@ -132,66 +71,14 @@ class Setu(db.Model):
参数:
:param pid: 图片pid
"""
query = await cls.query.where(cls.pid == pid).gino.first()
return_id = -1
query = await cls.get_or_none(pid=pid)
if query:
is_r18 = query.is_r18
num = await cls.get_image_count(is_r18)
x = await cls.query.where((cls.is_r18 == is_r18) & (cls.local_id == num - 1)).gino.first()
_tmp_local_id = x.local_id
if x:
x.update(local_id=query.local_id).apply()
await cls.delete.where(cls.pid == pid).gino.status()
return _tmp_local_id
return -1
@classmethod
async def update_setu_data(
cls,
pid: int,
*,
local_id: Optional[int] = None,
title: Optional[str] = None,
author: Optional[str] = None,
img_hash: Optional[str] = None,
img_url: Optional[str] = None,
tags: Optional[str] = None,
) -> bool:
"""
说明:
根据PID修改图片数据
参数:
:param local_id: 本地id
:param pid: 图片pid
:param title: 标题
:param author: 作者
:param img_hash: 图片hash值
:param img_url: 图片链接
:param tags: 图片标签
"""
query = cls.query.where(cls.pid == pid).with_for_update()
image_list = await query.gino.all()
if image_list:
for image in image_list:
if local_id:
await image.update(local_id=local_id).apply()
if title:
await image.update(title=title).apply()
if author:
await image.update(author=author).apply()
if img_hash:
await image.update(img_hash=img_hash).apply()
if img_url:
await image.update(img_url=img_url).apply()
if tags:
await image.update(tags=tags).apply()
return True
return False
@classmethod
async def get_all_setu(cls) -> List["Setu"]:
"""
说明:
获取所有图片对象
"""
return await cls.query.gino.all()
num = await cls.filter(is_r18=query.is_r18).count()
last_image = await cls.get_or_none(is_r18=query.is_r18, local_id=num - 1)
if last_image:
return_id = last_image.local_id
last_image.local_id = query.local_id
await last_image.save(update_fields=["local_id"])
await query.delete()
return return_id
+46 -44
View File
@@ -1,42 +1,40 @@
import random
from nonebot import on_command, on_regex
from services.log import logger
from models.sign_group_user import SignGroupUser
from nonebot.message import run_postprocessor
from nonebot.matcher import Matcher
from typing import Optional, Type, Any
from gino.exceptions import UninitializedError
import re
from typing import Any, Optional, Tuple, Type
from utils.message_builder import custom_forward_msg
from utils.utils import (
is_number,
)
from nonebot.typing import T_State
from nonebot import on_command, on_regex
from nonebot.adapters.onebot.v11 import (
Bot,
ActionFailed,
MessageEvent,
GroupMessageEvent,
PrivateMessageEvent,
Message,
Bot,
Event,
GroupMessageEvent,
Message,
MessageEvent,
PrivateMessageEvent,
)
from nonebot.matcher import Matcher
from nonebot.message import run_postprocessor
from nonebot.params import Command, CommandArg, RegexGroup
from nonebot.typing import T_State
from configs.config import NICKNAME, Config
from models.sign_group_user import SignGroupUser
from services.log import logger
from utils.manager import withdraw_message_manager
from utils.message_builder import custom_forward_msg
from utils.utils import is_number
from .._model import Setu
from .data_source import (
get_setu_list,
get_luoxiang,
search_online_setu,
get_setu_urls,
add_data_to_database,
check_local_exists_or_download,
find_img_index,
gen_message,
check_local_exists_or_download,
add_data_to_database,
get_setu_count,
get_luoxiang,
get_setu_list,
get_setu_urls,
search_online_setu,
)
from configs.config import Config, NICKNAME
from utils.manager import withdraw_message_manager
from nonebot.params import CommandArg, Command, RegexGroup
from typing import Tuple
import re
try:
import ujson as json
@@ -126,7 +124,7 @@ async def do_something(
await add_data_to_database(setu_data_list)
logger.info("色图数据自动存储数据库成功...")
setu_data_list = []
except UninitializedError:
except Exception:
pass
@@ -146,17 +144,18 @@ async def _(
):
msg = arg.extract_plain_text().strip()
if isinstance(event, GroupMessageEvent):
impression = (
await SignGroupUser.ensure(event.user_id, event.group_id)
).impression
user, _ = await SignGroupUser.get_or_create(
user_qq=event.user_id, group_id=event.group_id
)
impression = user.impression
luox = get_luoxiang(impression)
if luox:
await setu.finish(luox)
r18 = 0
r18 = False
num = 1
# 是否看r18
if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent):
r18 = 1
r18 = True
num = 10
elif cmd[0] == "色图r" and isinstance(event, GroupMessageEvent):
if not Config.get_config("send_setu", "ALLOW_GROUP_R18"):
@@ -164,18 +163,20 @@ async def _(
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
)
else:
r18 = 1
r18 = False
# 有 数字 的话先尝试本地色图id
if msg and is_number(msg):
setu_list, code = await get_setu_list(int(msg), r18=r18)
if code != 200:
await setu.finish(setu_list[0], at_sender=True)
setu_img, code = await check_local_exists_or_download(setu_list[0])
msg_id = await setu.send(gen_message(setu_list[0]) + setu_img, at_sender=True)
msg_id = await setu.send(
Message(gen_message(setu_list[0])) + setu_img, at_sender=True
)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送色图 {setu_list[0].local_id}.png"
f" 发送色图 {setu_list[0].local_id}.jpd"
)
if msg_id:
withdraw_message_manager.withdraw_message(
@@ -205,9 +206,10 @@ num_key = {
@setu_reg.handle()
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)
).impression
user, _ = await SignGroupUser.get_or_create(
user_qq=event.user_id, group_id=event.group_id
)
impression = user.impression
luox = get_luoxiang(impression)
if luox:
await setu.finish(luox, at_sender=True)
@@ -220,7 +222,7 @@ async def _(bot: Bot, event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGro
num = int(num)
except ValueError:
num = 1
await send_setu_handle(bot, setu_reg, event, "色图", tags, num, 0)
await send_setu_handle(bot, setu_reg, event, "色图", tags, num, False)
async def send_setu_handle(
@@ -230,7 +232,7 @@ async def send_setu_handle(
command: str,
msg: str,
num: int,
r18: int,
r18: bool,
):
global setu_data_list
# 非 id,在线搜索
@@ -240,7 +242,7 @@ async def send_setu_handle(
await matcher.finish("咳咳咳,虽然我很可爱,但是我木有自己的色图~~~有的话记得发我一份呀")
# 本地先拿图,下载失败补上去
setu_list, code = None, 200
setu_count = await get_setu_count(r18)
setu_count = await Setu.filter(is_r18=r18).count()
if (
not Config.get_config("send_setu", "ONLY_USE_LOCAL_SETU") and tags
) or setu_count <= 0:
+54 -51
View File
@@ -1,18 +1,22 @@
from configs.path_config import IMAGE_PATH, TEMP_PATH
from utils.message_builder import image
from services.log import logger
from utils.image_utils import get_img_hash, compressed_image
from utils.utils import change_img_md5
from asyncpg.exceptions import UniqueViolationError
from asyncio.exceptions import TimeoutError
from typing import List, Optional
from configs.config import NICKNAME, Config
from utils.http_utils import AsyncHttpx
from .._model import Setu
import asyncio
import os
import random
import re
from asyncio.exceptions import TimeoutError
from typing import List, Optional, Tuple, Union
from asyncpg.exceptions import UniqueViolationError
from nonebot.adapters.onebot.v11 import Message, MessageSegment
from configs.config import NICKNAME, Config
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import compressed_image, get_img_hash
from utils.message_builder import image
from utils.utils import change_img_md5
from .._model import Setu
try:
import ujson as json
@@ -28,11 +32,11 @@ host_pattern = re.compile(r"https?://([^/]+)")
# 获取url
async def get_setu_urls(
tags: List[str], num: int = 1, r18: int = 0, command: str = ""
) -> "List[str], List[str], List[tuple], int":
tags: List[str], num: int = 1, r18: bool = False, command: str = ""
) -> Tuple[List[str], List[str], List[tuple], int]:
tags = tags[:3] if len(tags) > 3 else tags
params = {
"r18": r18, # 添加r18参数 0为否,1为是,2为混合
"r18": 1 if r18 else 0, # 添加r18参数 0为否,1为是,2为混合
"tag": tags, # 若指定tag
"num": 20, # 一次返回的结果数量
"size": ["original"],
@@ -82,7 +86,7 @@ headers = {
async def search_online_setu(
url_: str, id_: Optional[int] = None, path_: Optional[str] = None
) -> "MessageSegment, int":
) -> Tuple[Union[MessageSegment, str], int]:
"""
下载色图
:param url_: 色图url
@@ -108,10 +112,7 @@ async def search_online_setu(
):
continue
if id_ is not None:
if (
os.path.getsize(path_ / f"{index}.jpg")
> 1024 * 1024 * 1.5
):
if os.path.getsize(path_ / f"{index}.jpg") > 1024 * 1024 * 1.5:
compressed_image(
path_ / f"{index}.jpg",
)
@@ -126,7 +127,9 @@ async def search_online_setu(
# 检测本地是否有id涩图,无的话则下载
async def check_local_exists_or_download(setu_image: Setu) -> "MessageSegment, int":
async def check_local_exists_or_download(
setu_image: Setu,
) -> Tuple[MessageSegment, int]:
path_ = None
id_ = None
if Config.get_config("send_setu", "DOWNLOAD_SETU"):
@@ -148,27 +151,28 @@ async def add_data_to_database(lst: List[tuple]):
if tmp:
for x in tmp:
try:
r18 = 1 if "R-18" in x[5] else 0
idx = await Setu.get_image_count(r18)
await Setu.add_setu_data(
idx,
x[0],
x[1],
x[2],
x[3],
x[4],
x[5],
)
idx = await Setu.filter(is_r18="R-18" in x[5]).count()
if not await Setu.exists(pid=x[2], img_url=x[4]):
await Setu.create(
local_id=idx,
title=x[0],
author=x[1],
pid=x[2],
img_hash=x[3],
img_url=x[4],
tags=x[5],
is_r18="R-18" in x[5],
)
except UniqueViolationError:
pass
# 拿到本地色图列表
async def get_setu_list(
index: Optional[int] = None, tags: Optional[List[str]] = None, r18: int = 0
) -> "list, int":
index: Optional[int] = None, tags: Optional[List[str]] = None, r18: bool = False
) -> Tuple[list, int]:
if index:
image_count = await Setu.get_image_count(r18) - 1
image_count = await Setu.filter(is_r18=r18).count() - 1
if index < 0 or index > image_count:
return [f"超过当前上下限!({image_count})"], 999
image_list = [await Setu.query_image(index, r18=r18)]
@@ -182,44 +186,44 @@ async def get_setu_list(
# 初始化消息
def gen_message(setu_image: Setu, img_msg: bool = False) -> str:
def gen_message(
setu_image: Setu, img_msg: bool = False
) -> Union[Message, MessageSegment]:
local_id = setu_image.local_id
title = setu_image.title
author = setu_image.author
pid = setu_image.pid
path_ = r18_path if setu_image.is_r18 else path
image_path = IMAGE_PATH / path_ / f"{local_id}.jpg"
if Config.get_config("send_setu", "SHOW_INFO"):
return (
return Message(
f"id:{local_id}\n"
f"title:{title}\n"
f"author:{author}\n"
f"PID:{pid}\n"
f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
f"PID:{pid}\n" + image(image_path)
)
return f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
return image(image_path)
# 罗翔老师!
def get_luoxiang(impression):
probability = (
impression + Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100
float(impression)
+ Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100
)
if probability < random.randint(1, 101):
return (
"我为什么要给你发这个?"
+ image(random.choice(os.listdir(IMAGE_PATH / "luoxiang")), "luoxiang")
+ image(
IMAGE_PATH
/ "luoxiang"
/ random.choice(os.listdir(IMAGE_PATH / "luoxiang"))
)
+ f"\n(快向{NICKNAME}签到提升好感度吧!)"
)
return None
async def get_setu_count(r18: int) -> int:
"""
获取色图数量
:param r18: r18类型
"""
return await Setu.get_image_count(r18)
async def find_img_index(img_url, user_id):
if not await AsyncHttpx.download_file(
img_url,
@@ -228,8 +232,7 @@ async def find_img_index(img_url, user_id):
):
return "检索图片下载上失败..."
img_hash = str(get_img_hash(TEMP_PATH / f"{user_id}_find_setu_index.jpg"))
setu_img = await Setu.get_image_in_hash(img_hash)
if setu_img:
if setu_img := await Setu.get_or_none(img_hash=img_hash):
return (
f"id:{setu_img.local_id}\n"
f"title:{setu_img.title}\n"
+41 -36
View File
@@ -1,18 +1,21 @@
from configs.path_config import IMAGE_PATH, TEXT_PATH, TEMP_PATH
from services.log import logger
from datetime import datetime
from utils.image_utils import compressed_image, get_img_hash
from utils.utils import get_bot
from PIL import UnidentifiedImageError
from .._model import Setu
from asyncpg.exceptions import UniqueViolationError
from configs.config import Config
from utils.http_utils import AsyncHttpx
from nonebot import Driver
import nonebot
import os
import ujson as json
import shutil
from datetime import datetime
import nonebot
import ujson as json
from asyncpg.exceptions import UniqueViolationError
from nonebot import Driver
from PIL import UnidentifiedImageError
from configs.config import Config
from configs.path_config import IMAGE_PATH, TEMP_PATH, TEXT_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import compressed_image, get_img_hash
from utils.utils import change_pixiv_image_links, get_bot
from .._model import Setu
driver: Driver = nonebot.get_driver()
@@ -47,15 +50,17 @@ async def update_old_setu_data():
)
# idx = r18_index if 'R-18' in data[x]["tags"] else index
try:
await Setu.add_setu_data(
idx,
data[x]["title"],
data[x]["author"],
data[x]["pid"],
data[x]["img_hash"],
img_url,
",".join(data[x]["tags"]),
)
if not await Setu.exists(pid=data[x]["pid"], url=img_url):
await Setu.create(
local_id=idx,
title=data[x]["title"],
author=data[x]["author"],
pid=data[x]["pid"],
img_hash=data[x]["img_hash"],
img_url=img_url,
is_r18="R-18" in data[x]["tags"],
tags=",".join(data[x]["tags"]),
)
count += 1
if "R-18" in data[x]["tags"]:
r18_index += 1
@@ -94,7 +99,7 @@ async def update_setu_img(flag: bool = False):
更新色图
:param flag: 是否手动更新
"""
image_list = await Setu.get_all_setu()
image_list = await Setu.all().order_by("local_id")
image_list.reverse()
_success = 0
error_info = []
@@ -110,12 +115,7 @@ async def update_setu_img(flag: bool = False):
temp_file = TEMP_PATH / f"{image.local_id}.jpg"
if temp_file.exists():
temp_file.unlink()
url_ = image.img_url
ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
if ws_url:
url_ = url_.replace("i.pximg.net", ws_url).replace(
"i.pixiv.cat", ws_url
)
url_ = change_pixiv_image_links(image.img_url)
try:
if not await AsyncHttpx.download_file(
url_, TEMP_PATH / f"{image.local_id}.jpg"
@@ -146,15 +146,20 @@ async def update_setu_img(flag: bool = False):
logger.warning(f"文件 {image.local_id}.jpg 不存在,跳过...")
continue
img_hash = str(get_img_hash(f"{path}/{image.local_id}.jpg"))
await Setu.update_setu_data(image.pid, img_hash=img_hash)
image.img_hash = img_hash
await image.save(update_fields=["img_hash"])
# await Setu.update_setu_data(image.pid, img_hash=img_hash)
except UnidentifiedImageError:
# 图片已删除
with open(local_image, 'r') as f:
if '404 Not Found' in f.read():
max_num = await Setu.delete_image(image.pid)
local_image.unlink()
os.rename(path / f"{max_num}.jpg", local_image)
logger.warning(f"更新色图 PID:{image.pid} 404,已删除并替换")
unlink = False
with open(local_image, "r") as f:
if "404 Not Found" in f.read():
unlink = True
if unlink:
local_image.unlink()
max_num = await Setu.delete_image(image.pid)
os.rename(path / f"{max_num}.jpg", local_image)
logger.warning(f"更新色图 PID:{image.pid} 404,已删除并替换")
except Exception as e:
_success -= 1
logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}")
+20 -18
View File
@@ -1,9 +1,9 @@
from models.sign_group_user import SignGroupUser
from configs.config import Config
from nonebot import Driver
from utils.decorator.shop import shop_register, NotMeetUseConditionsException
import nonebot
from nonebot import Driver
from configs.config import Config
from models.sign_group_user import SignGroupUser
from utils.decorator.shop import NotMeetUseConditionsException, shop_register
driver: Driver = nonebot.get_driver()
@@ -22,13 +22,18 @@ async def _():
"下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)",
"下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)",
),
load_status=Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"),
icon=("favorability_card_1.png", "favorability_card_2.png", "favorability_card_3.png"),
** {"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
load_status=bool(Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS")),
icon=(
"favorability_card_1.png",
"favorability_card_2.png",
"favorability_card_3.png",
),
**{"好感度双倍加持卡Ⅰ_prob": 0.1, "好感度双倍加持卡Ⅱ_prob": 0.2, "好感度双倍加持卡Ⅲ_prob": 0.3},
)
async def sign_card(user_id: int, group_id: int, prob: float):
user = await SignGroupUser.ensure(user_id, group_id)
await user.update(add_probability=prob).apply()
user, _ = await SignGroupUser.get_or_create(user_qq=user_id, group_id=group_id)
user.add_probability = prob
await user.save(update_fields=["add_probability"])
@shop_register(
name="测试道具A",
@@ -38,20 +43,17 @@ async def _():
icon="sword.png",
)
async def _(user_id: int, group_id: int):
print(user_id, group_id, '使用测试道具')
print(user_id, group_id, "使用测试道具")
@shop_register.before_handle(name="测试道具A", load_status=False)
async def _(user_id: int, group_id: int):
print(user_id, group_id, '第一个使用前函数(before handle)')
print(user_id, group_id, "第一个使用前函数(before handle)")
@shop_register.before_handle(name="测试道具A", load_status=False)
async def _(user_id: int, group_id: int):
print(user_id, group_id, '第二个使用前函数(before handle)222')
raise NotMeetUseConditionsException("太笨了!") # 抛出异常,阻断使用,并返回信息
print(user_id, group_id, "第二个使用前函数(before handle)222")
raise NotMeetUseConditionsException("太笨了!") # 抛出异常,阻断使用,并返回信息
@shop_register.after_handle(name="测试道具A", load_status=False)
async def _(user_id: int, group_id: int):
print(user_id, group_id, '第一个使用后函数(after handle)')
print(user_id, group_id, "第一个使用后函数(after handle)")
+51 -55
View File
@@ -1,23 +1,25 @@
from datetime import datetime, timedelta
from models.sign_group_user import SignGroupUser
from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser
from configs.config import NICKNAME
from nonebot.adapters.onebot.v11 import MessageSegment
from utils.image_utils import BuildImage, BuildMat
from services.db_context import db
from .utils import get_card, SIGN_TODAY_CARD_PATH
from typing import Optional
from services.log import logger
from .random_event import random_event
from utils.data_utils import init_rank
from utils.utils import get_user_avatar
from io import BytesIO
import random
import math
import asyncio
import secrets
import math
import os
import random
import secrets
from datetime import datetime, timedelta
from io import BytesIO
from typing import Optional
from nonebot.adapters.onebot.v11 import MessageSegment
from configs.config import NICKNAME
from models.bag_user import BagUser
from models.group_member_info import GroupInfoUser
from models.sign_group_user import SignGroupUser
from services.log import logger
from utils.data_utils import init_rank
from utils.image_utils import BuildImage, BuildMat
from utils.utils import get_user_avatar
from .random_event import random_event
from .utils import SIGN_TODAY_CARD_PATH, get_card
async def group_user_check_in(
@@ -25,18 +27,17 @@ async def group_user_check_in(
) -> MessageSegment:
"Returns string describing the result of checking in"
present = datetime.now()
async with db.transaction():
# 取得相应用户
user = await SignGroupUser.ensure(user_qq, group, for_update=True)
# 如果同一天签到过,特殊处理
if (
user.checkin_time_last + timedelta(hours=8)
).date() >= present.date() or f"{user}_{group}_sign_{datetime.now().date()}" in os.listdir(
SIGN_TODAY_CARD_PATH
):
gold = await BagUser.get_gold(user_qq, group)
return await get_card(user, nickname, -1, gold, "")
return await _handle_check_in(nickname, user_qq, group, present) # ok
# 取得相应用户
user, is_create = await SignGroupUser.get_or_create(user_qq=user_qq, group_id=group)
# 如果同一天签到过,特殊处理
if not is_create and (
user.checkin_time_last.date() >= present.date()
or f"{user}_{group}_sign_{datetime.now().date()}"
in os.listdir(SIGN_TODAY_CARD_PATH)
):
gold = await BagUser.get_gold(user_qq, group)
return await get_card(user, nickname, -1, gold, "")
return await _handle_check_in(nickname, user_qq, group, present) # ok
async def check_in_all(nickname: str, user_qq: int):
@@ -47,40 +48,39 @@ async def check_in_all(nickname: str, user_qq: int):
:param nickname: 昵称
:param user_qq: 用户qq
"""
async with db.transaction():
present = datetime.now()
for u in await SignGroupUser.get_user_all_data(user_qq):
group = u.group_id
if not ((
u.checkin_time_last + timedelta(hours=8)
).date() >= present.date() or f"{u}_{group}_sign_{datetime.now().date()}" in os.listdir(
SIGN_TODAY_CARD_PATH
)):
await _handle_check_in(nickname, user_qq, group, present)
present = datetime.now()
for u in await SignGroupUser.filter(user_qq=user_qq).all():
group = u.group_id
if not (
u.checkin_time_last.date() >= present.date()
or f"{u}_{group}_sign_{datetime.now().date()}"
in os.listdir(SIGN_TODAY_CARD_PATH)
):
await _handle_check_in(nickname, user_qq, group, present)
async def _handle_check_in(
nickname: str, user_qq: int, group: int, present: datetime
) -> MessageSegment:
user = await SignGroupUser.ensure(user_qq, group, for_update=True)
impression_added = (secrets.randbelow(99)+1)/100
user, _ = await SignGroupUser.get_or_create(user_qq=user_qq, group_id=group)
impression_added = (secrets.randbelow(99) + 1) / 100
critx2 = random.random()
add_probability = user.add_probability
add_probability = float(user.add_probability)
specify_probability = user.specify_probability
if critx2 + add_probability > 0.97:
impression_added *= 2
elif critx2 < specify_probability:
impression_added *= 2
await SignGroupUser.sign(user, impression_added, present)
await SignGroupUser.sign(user, impression_added)
gold = random.randint(1, 100)
gift, gift_type = random_event(user.impression)
gift, gift_type = random_event(float(user.impression))
if gift_type == "gold":
await BagUser.add_gold(user_qq, group, gold + gift)
gift = f"额外金币 + {gift}"
else:
await BagUser.add_gold(user_qq, group, gold)
await BagUser.add_property(user_qq, group, gift)
gift += ' + 1'
gift += " + 1"
logger.info(
f"(USER {user.user_qq}, GROUP {user.group_id})"
@@ -95,7 +95,7 @@ async def _handle_check_in(
async def group_user_check(nickname: str, user_qq: int, group: int) -> MessageSegment:
# heuristic: if users find they have never checked in they are probable to check in
user = await SignGroupUser.ensure(user_qq, group)
user, _ = await SignGroupUser.get_or_create(user_qq=user_qq, group_id=group)
gold = await BagUser.get_gold(user_qq, group)
return await get_card(user, nickname, None, gold, "", is_card_view=True)
@@ -171,18 +171,14 @@ async def _pst(users: list, impressions: list, groups: list):
impressions.pop(index)
users.pop(index)
groups.pop(index)
try:
user_name = (
await GroupInfoUser.get_member_info(user, group)
).user_name
except AttributeError:
if user_ := await GroupInfoUser.get_or_none(user_qq=user, group_id=group):
user_name = user_.user_name
else:
user_name = f"我名字呢?"
user_name = user_name if len(user_name) < 11 else user_name[:10] + "..."
ava = await get_user_avatar(user)
if ava:
ava = BuildImage(
50, 50, background=BytesIO(ava)
)
ava = BuildImage(50, 50, background=BytesIO(ava))
else:
ava = BuildImage(50, 50, color="white")
ava.circle()
+11 -13
View File
@@ -1,11 +1,12 @@
from configs.config import Config
import random
from typing import Tuple, Union
from configs.config import Config
PROB_DATA = None
def random_event(impression: float) -> 'Union[str, int], str':
def random_event(impression: float) -> Tuple[Union[str, int], str]:
"""
签到随机事件
:param impression: 好感度
@@ -14,20 +15,17 @@ def random_event(impression: float) -> 'Union[str, int], str':
global PROB_DATA
if not PROB_DATA:
PROB_DATA = {
Config.get_config("sign_in", "SIGN_CARD3_PROB"): '好感度双倍加持卡Ⅲ',
Config.get_config("sign_in", "SIGN_CARD2_PROB"): '好感度双倍加持卡Ⅱ',
Config.get_config("sign_in", "SIGN_CARD1_PROB"): '好感度双倍加持卡Ⅰ'
Config.get_config("sign_in", "SIGN_CARD3_PROB"): "好感度双倍加持卡Ⅲ",
Config.get_config("sign_in", "SIGN_CARD2_PROB"): "好感度双倍加持卡Ⅱ",
Config.get_config("sign_in", "SIGN_CARD1_PROB"): "好感度双倍加持卡Ⅰ",
}
rand = random.random() - impression / 1000
for prob in PROB_DATA.keys():
if rand <= prob:
return PROB_DATA[prob], 'props'
gold = random.randint(1, random.randint(1, int(1 if impression < 1 else impression)))
return PROB_DATA[prob], "props"
gold = random.randint(
1, random.randint(1, int(1 if impression < 1 else impression))
)
max_sign_gold = Config.get_config("sign_in", "MAX_SIGN_GOLD")
gold = max_sign_gold if gold > max_sign_gold else gold
return gold, 'gold'
return gold, "gold"
+50 -33
View File
@@ -1,31 +1,33 @@
from .config import (
SIGN_RESOURCE_PATH,
SIGN_TODAY_CARD_PATH,
SIGN_BORDER_PATH,
SIGN_BACKGROUND_PATH,
lik2level,
lik2relation,
level2attitude,
weekdays,
)
from models.sign_group_user import SignGroupUser
from models.group_member_info import GroupInfoUser
import asyncio
import os
import random
from datetime import datetime
from io import BytesIO
from pathlib import Path
from typing import List, Optional
import nonebot
from nonebot import Driver
from nonebot.adapters.onebot.v11 import MessageSegment
from configs.config import Config
from utils.utils import get_user_avatar
from configs.config import NICKNAME, Config
from configs.path_config import IMAGE_PATH
from models.group_member_info import GroupInfoUser
from models.sign_group_user import SignGroupUser
from utils.image_utils import BuildImage
from utils.message_builder import image
from configs.config import NICKNAME
from pathlib import Path
from datetime import datetime
from typing import Optional, List
from nonebot import Driver
from io import BytesIO
import asyncio
import random
import nonebot
import os
from utils.utils import get_user_avatar
from .config import (
SIGN_BACKGROUND_PATH,
SIGN_BORDER_PATH,
SIGN_RESOURCE_PATH,
SIGN_TODAY_CARD_PATH,
level2attitude,
lik2level,
lik2relation,
weekdays,
)
driver: Driver = nonebot.get_driver()
@@ -34,10 +36,13 @@ driver: Driver = nonebot.get_driver()
async def init_image():
SIGN_RESOURCE_PATH.mkdir(parents=True, exist_ok=True)
SIGN_TODAY_CARD_PATH.mkdir(exist_ok=True, parents=True)
await GroupInfoUser.add_member_info(114514, 114514, "", datetime.min, 0)
_u = await GroupInfoUser.get_member_info(114514, 114514)
if _u.uid is None:
await _u.update(uid=0).apply()
if not await GroupInfoUser.get_or_none(user_qq=114514):
await GroupInfoUser.create(
user_qq=114514,
group_id=114514,
user_name="",
uid=0,
)
generate_progress_bar_pic()
clear_sign_data_pic()
@@ -58,7 +63,12 @@ async def get_card(
Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.group_id}_{_type}_{date}.png"
)
if card_file.exists():
return image(f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card")
return image(
IMAGE_PATH
/ "sign"
/ "today_card"
/ f"{user_id}_{user.group_id}_{_type}_{date}.png"
)
else:
if add_impression == -1:
card_file = (
@@ -67,8 +77,10 @@ async def get_card(
)
if card_file.exists():
return image(
f"{user_id}_{user.group_id}_view_{date}.png",
"sign/today_card",
IMAGE_PATH
/ "sign"
/ "today_card"
/ f"{user_id}_{user.group_id}_view_{date}.png"
)
is_card_view = True
ava = BytesIO(await get_user_avatar(user_id))
@@ -244,7 +256,7 @@ def _generate_card(
)
today_data.text(
(0, 50),
f"色图概率:{(default_setu_prob + user.impression if user.impression < 100 else 100):.2f}%",
f"色图概率:{(default_setu_prob + float(user.impression) if user.impression < 100 else 100):.2f}%",
)
today_data.text((0, 75), f"开箱次数:{(20 + int(user.impression / 3))}")
_type = "view"
@@ -285,7 +297,12 @@ def _generate_card(
bk.paste(today_data, (580, 220), True)
bk.paste(watermark, (15, 400), True)
bk.save(SIGN_TODAY_CARD_PATH / f"{user_id}_{user.group_id}_{_type}_{data}.png")
return image(f"{user_id}_{user.group_id}_{_type}_{data}.png", "sign/today_card")
return image(
IMAGE_PATH
/ "sign"
/ "today_card"
/ f"{user_id}_{user.group_id}_{_type}_{data}.png"
)
def generate_progress_bar_pic():
+20 -27
View File
@@ -1,30 +1,23 @@
from datetime import datetime
from typing import Optional
from services.db_context import db
class Statistics(db.Model):
__tablename__ = "statistics"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger())
plugin_name = db.Column(db.String(), nullable=False)
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
from tortoise import fields
@classmethod
async def add_statistic(cls, user_qq: int, group_id: Optional[int], plugin_name: str):
"""
说明:
添加记录
参数:
:param user_qq: qq
:param group_id: 群号
:param plugin_name: 插件model
"""
await cls.create(
user_qq=user_qq,
group_id=group_id,
plugin_name=plugin_name,
create_time=datetime.now(),
)
from services.db_context import Model
class Statistics(Model):
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField(null=True)
"""群聊id"""
plugin_name = fields.CharField(255)
"""插件名称"""
create_time = fields.DatetimeField(auto_now=True)
"""添加日期"""
class Meta:
table = "statistics"
table_description = "用户权限数据库"
+13 -11
View File
@@ -1,14 +1,16 @@
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, Message
from models.group_info import GroupInfo
from configs.path_config import DATA_PATH, IMAGE_PATH
from nonebot.params import CommandArg, Command
from utils.image_utils import BuildMat
from utils.message_builder import image
from utils.manager import plugins2settings_manager
from typing import Tuple
import asyncio
import os
from typing import Tuple
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent
from nonebot.params import Command, CommandArg
from configs.path_config import DATA_PATH, IMAGE_PATH
from models.group_info import GroupInfo
from utils.image_utils import BuildMat
from utils.manager import plugins2settings_manager
from utils.message_builder import image
try:
import ujson as json
@@ -160,8 +162,8 @@ async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg
day_index = data["day_index"]
data = data[arg][key]
if _type == "group":
name = await GroupInfo.get_group_info(event.group_id)
name = name.group_name if name else str(event.group_id)
group = await GroupInfo.filter(group_id=event.group_id).first()
name = name.group_name if group else str(event.group_id)
else:
name = event.sender.card or event.sender.nickname
img = await generate_statistics_img(data, arg, name, plugin, day_index)
+12 -9
View File
@@ -1,12 +1,14 @@
from configs.path_config import DATA_PATH
from datetime import datetime
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
from nonebot.matcher import Matcher
from nonebot.message import run_postprocessor
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
from datetime import datetime
from nonebot.typing import Optional, T_State
from configs.path_config import DATA_PATH
from utils.manager import plugins2settings_manager
from utils.utils import scheduler
from nonebot.typing import Optional
from ._model import Statistics
try:
@@ -99,10 +101,11 @@ async def _(
and matcher.priority not in [1, 999]
and matcher.plugin_name not in ["update_info", "statistics_handle"]
):
await Statistics.add_statistic(
event.user_id,
event.group_id if isinstance(event, GroupMessageEvent) else None,
matcher.plugin_name,
await Statistics.create(
user_qq=event.user_id,
group_id=getattr(event, "group_id", None),
plugin_name=matcher.plugin_name,
create_time=datetime.now(),
)
module = matcher.plugin_name
day_index = _prefix_count_dict["day_index"]
+28 -20
View File
@@ -1,20 +1,21 @@
from nonebot import on_command
from PIL import Image, ImageFilter
from utils.message_builder import image
from configs.path_config import TEMP_PATH, IMAGE_PATH
from services.log import logger
from nonebot.rule import to_me
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message
from nonebot.typing import T_State
from utils.utils import get_message_img, is_number
from nonebot.params import CommandArg, Arg, ArgStr, Depends
from utils.image_utils import BuildImage, pic2b64
from configs.config import NICKNAME
from utils.http_utils import AsyncHttpx
from typing import Union
import cv2
import numpy as np
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message, MessageEvent
from nonebot.params import Arg, ArgStr, CommandArg, Depends
from nonebot.rule import to_me
from nonebot.typing import T_State
from PIL import Image, ImageFilter
from configs.config import NICKNAME
from configs.path_config import IMAGE_PATH, TEMP_PATH
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.image_utils import BuildImage, pic2b64
from utils.message_builder import image
from utils.utils import get_message_img, is_number
__zx_plugin_name__ = "各种图片简易操作"
__plugin_usage__ = """
@@ -88,9 +89,7 @@ update_img_help.save(IMAGE_PATH / "update_img_help.png")
def parse_key(key: str):
async def _key_parser(
state: T_State, inp: Union[Message, str] = Arg(key)
):
async def _key_parser(state: T_State, inp: Union[Message, str] = Arg(key)):
if key != "img_list" and isinstance(inp, Message):
inp = inp.extract_plain_text().strip()
if inp in ["取消", "算了"]:
@@ -132,6 +131,7 @@ def parse_key(key: str):
if not get_message_img(inp):
await update_img.reject_arg("img_list", "没图?没图?没图?来图速来!")
state[key] = inp
return _key_parser
@@ -167,10 +167,18 @@ async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
state["img_list"] = event.message
@update_img.got("method", prompt=f"要使用图片的什么操作呢?{method_str}", parameterless=[Depends(parse_key("method"))])
@update_img.got("x", prompt="[宽度? 比率? 旋转角度? 底色?]", parameterless=[Depends(parse_key("x"))])
@update_img.got(
"method",
prompt=f"要使用图片的什么操作呢?{method_str}",
parameterless=[Depends(parse_key("method"))],
)
@update_img.got(
"x", prompt="[宽度? 比率? 旋转角度? 底色?]", parameterless=[Depends(parse_key("x"))]
)
@update_img.got("y", prompt="[长度? 0 0 底色?]", parameterless=[Depends(parse_key("y"))])
@update_img.got("img_list", prompt="图呢图呢图呢图呢?GKD!", parameterless=[Depends(parse_key("img_list"))])
@update_img.got(
"img_list", prompt="图呢图呢图呢图呢?GKD!", parameterless=[Depends(parse_key("img_list"))]
)
async def _(
event: MessageEvent,
state: T_State,
@@ -285,7 +293,7 @@ async def _(
img[i, j] = color
cv2.imwrite(TEMP_PATH / f"{event.user_id}_{k}_ok_update.png", img)
for i in range(index):
result += image(f"{event.user_id}_{i}_ok_update.png", "temp")
result += image(TEMP_PATH / f"{event.user_id}_{i}_ok_update.png")
if is_number(method):
method = method_list[int(method) - 1]
logger.info(
+19 -15
View File
@@ -1,7 +1,8 @@
from utils.manager import requests_manager
from ..auth import token_to_user, Depends, User
from utils.utils import get_bot
from models.group_info import GroupInfo
from utils.manager import requests_manager
from utils.utils import get_bot
from ..auth import Depends, User, token_to_user
from ..config import *
@@ -39,18 +40,21 @@ async def _(parma: RequestParma, user: User = Depends(token_to_user)) -> Result:
if bot := get_bot():
if parma.handle == "approve":
if parma.type == "group":
rid = requests_manager.get_group_id(parma.id)
if await GroupInfo.get_group_info(rid):
await GroupInfo.set_group_flag(rid, 1)
else:
group_info = await bot.get_group_info(group_id=rid)
await GroupInfo.add_group_info(
rid,
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1,
)
if rid := requests_manager.get_group_id(parma.id):
# await GroupInfo.update_or_create(defaults={"group_flag": 1}, )
if group := await GroupInfo.filter(group_id=rid).first():
await group.update_or_create(group_flag=1)
else:
group_info = await bot.get_group_info(group_id=rid)
await GroupInfo.update_or_create(
group_id=group_info["group_id"],
defaults={
"group_name": group_info["group_name"],
"max_member_count": group_info["max_member_count"],
"member_count": group_info["member_count"],
"group_flag": 1,
},
)
flag = await requests_manager.approve(bot, parma.id, parma.type)
elif parma.handle == "refuse":
flag = await requests_manager.refused(bot, parma.id, parma.type)
+130 -162
View File
@@ -1,47 +1,63 @@
import random
import re
import time
from nonebot.internal.adapter.template import MessageTemplate
from datetime import datetime
from typing import Any, List, Optional, Tuple, Union
from nonebot.adapters.onebot.v11 import (
GroupMessageEvent,
Message,
MessageEvent,
GroupMessageEvent,
MessageSegment,
)
from services.db_context import db
from typing import Optional, List, Union, Tuple, Any
from datetime import datetime
from configs.path_config import DATA_PATH
import random
from ._config import int2type
from utils.image_utils import get_img_hash
from utils.http_utils import AsyncHttpx
import re
from nonebot.internal.adapter.template import MessageTemplate
from tortoise import Tortoise, fields
from tortoise.expressions import Q, RawSQL
from utils.message_builder import image, face, at
from configs.path_config import DATA_PATH
from services.db_context import Model
from utils.http_utils import AsyncHttpx
from utils.image_utils import get_img_hash
from utils.message_builder import at, face, image
from utils.utils import get_message_img
from ._config import int2type
path = DATA_PATH / "word_bank"
class WordBank(db.Model):
__tablename__ = "word_bank2"
class WordBank(Model):
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.Integer())
word_scope = db.Column(
db.Integer(), nullable=False, default=0
) # 生效范围 0: 全局 1: 群聊 2: 私聊
word_type = db.Column(
db.Integer(), nullable=False, default=0
) # 词条类型 0: 完全匹配 1: 模糊 2: 正则 3: 图片
status = db.Column(db.Boolean(), nullable=False, default=True) # 词条状态
problem = db.Column(db.String(), nullable=False) # 问题,为图片时使用图片hash
answer = db.Column(db.String(), nullable=False) # 回答
placeholder = db.Column(db.String()) # 占位符
image_path = db.Column(db.String()) # 使用图片作为问题时图片存储的路径
to_me = db.Column(db.String()) # 使用图片作为问题时图片存储的路径
create_time = db.Column(db.DateTime(), nullable=False)
update_time = db.Column(db.DateTime(), nullable=False)
id = fields.IntField(pk=True, generated=True, auto_increment=True)
"""自增id"""
user_qq = fields.BigIntField()
"""用户id"""
group_id = fields.BigIntField(null=True)
"""群聊id"""
word_scope = fields.IntField(default=0)
"""生效范围 0: 全局 1: 群聊 2: 私聊"""
word_type = fields.IntField(default=0)
"""词条类型 0: 完全匹配 1: 模糊 2: 正则 3: 图片"""
status = fields.BooleanField()
"""词条状态"""
problem = fields.TextField()
"""问题,为图片时使用图片hash"""
answer = fields.TextField()
"""回答"""
placeholder = fields.TextField(null=True)
"""占位符"""
image_path = fields.TextField(null=True)
"""使用图片作为问题时图片存储的路径"""
to_me = fields.CharField(255, null=True)
"""昵称开头时存储的昵称"""
create_time = fields.DatetimeField(auto_now=True)
"""创建时间"""
update_time = fields.DatetimeField(auto_now_add=True)
"""更新时间"""
class Meta:
table = "word_bank2"
table_description = "词条数据库"
@classmethod
async def exists(
@@ -64,18 +80,18 @@ class WordBank(db.Model):
:param word_scope: 词条范围
:param word_type: 词条类型
"""
query = cls.query.where(cls.problem == problem)
query = cls.filter(problem=problem)
if user_id:
query = query.where(cls.user_qq == user_id)
query = query.filter(user_qq=user_id)
if group_id:
query = query.where(cls.group_id == group_id)
query = query.filter(group_id=group_id)
if answer:
query = query.where(cls.answer == answer)
if word_type:
query = query.where(cls.word_type == word_type)
if word_scope:
query = query.where(cls.word_scope == word_scope)
return bool(await query.gino.first())
query = query.filter(answer=answer)
if word_type is not None:
query = query.filter(word_type=word_type)
if word_scope is not None:
query = query.filter(word_scope=word_scope)
return bool(await query.first())
@classmethod
async def add_problem_answer(
@@ -86,7 +102,7 @@ class WordBank(db.Model):
word_type: int,
problem: Union[str, Message],
answer: Union[str, Message],
to_me_nickname: str = None
to_me_nickname: Optional[str] = None,
):
"""
说明:
@@ -112,7 +128,9 @@ class WordBank(db.Model):
problem = str(get_img_hash(_file))
image_path = f"problem/{group_id}/{user_id}_{int(time.time())}.jpg"
answer, _list = await cls._answer2format(answer, user_id, group_id)
if not await cls.exists(user_id, group_id, problem, answer, word_scope, word_type):
if not await cls.exists(
user_id, group_id, problem, answer, word_scope, word_type
):
await cls.create(
user_qq=user_id,
group_id=group_id,
@@ -125,7 +143,7 @@ class WordBank(db.Model):
placeholder=",".join(_list),
create_time=datetime.now().replace(microsecond=0),
update_time=datetime.now().replace(microsecond=0),
to_me=to_me_nickname
to_me=to_me_nickname,
)
@classmethod
@@ -152,7 +170,7 @@ class WordBank(db.Model):
text += seg.data["text"]
elif seg.type == "face":
text += f"[face:placeholder_{index}]"
_list.append(seg.data['id'])
_list.append(seg.data["id"])
elif seg.type == "at":
text += f"[at:placeholder_{index}]"
_list.append(seg.data["qq"])
@@ -187,12 +205,12 @@ class WordBank(db.Model):
if query:
answer = query.answer
else:
query = await cls.query.where(
(cls.problem == problem)
& (cls.user_qq == user_id)
& (cls.group_id == group_id)
& (cls.answer == answer)
).gino.first()
query = await cls.get_or_none(
problem=problem,
user_qq=user_id,
group_id=group_id,
answer=answer,
)
if query and query.placeholder:
type_list = re.findall(rf"\[(.*?):placeholder_.*?]", answer)
temp_answer = re.sub(rf"\[(.*?):placeholder_.*?]", "{}", answer)
@@ -208,7 +226,7 @@ class WordBank(db.Model):
return answer
@classmethod
async def check(
async def check_problem(
cls,
event: MessageEvent,
problem: str,
@@ -224,60 +242,35 @@ class WordBank(db.Model):
:param word_scope: 词条范围
:param word_type: 词条类型
"""
query = cls.query
sql_text = "SELECT * FROM public.word_bank2 where 1 = 1"
# 救命!!没找到gino的正则表达式方法,暂时使用sql语句
query = cls
if isinstance(event, GroupMessageEvent):
if word_scope:
query = query.where(cls.word_scope == word_scope)
sql_text += f" and word_scope = {word_scope}"
query = query.filter(word_scope=word_scope)
else:
query = query.where(
(cls.group_id == event.group_id) | (cls.word_scope == 0)
)
sql_text += f" and (group_id = {event.group_id} or word_scope = 0)"
query = query.filter(Q(group_id=event.group_id) | Q(word_scope=0))
else:
query = query.where((cls.word_scope == 2) | (cls.word_scope == 0))
sql_text += f" and (word_scope = 2 or word_scope = 0)"
query = query.filter(Q(cword_scope=2) | Q(word_scope=0))
if word_type:
query = query.where(cls.word_scope == word_type)
sql_text += f" and word_scope = {word_scope}"
query = query.filter(word_scope=word_type)
# 完全匹配
if await query.where(
((cls.word_type == 0) | (cls.word_type == 3)) & (cls.problem == problem)
).gino.first():
return query.where(
((cls.word_type == 0) | (cls.word_type == 3)) & (cls.problem == problem)
)
if data_list := await query.filter(
Q(Q(word_type=0) | Q(word_type=3)), Q(problem=problem)
).all():
return data_list
db = Tortoise.get_connection("default")
# 模糊匹配
if await db.first(
db.text(
sql_text
+ f" and word_type = 1 and :problem like '%' || problem || '%';"
),
problem=problem,
):
return (
sql_text
+ f" and word_type = 1 and :problem like '%' || problem || '%';"
)
# 正则匹配
if await db.first(
db.text(
sql_text
+ f" and word_type = 2 and word_scope != 999 and :problem ~ problem;"
),
problem=problem,
):
return (
sql_text
+ f" and word_type = 2 and word_scope != 999 and :problem ~ problem;"
)
# if await db.first(
# db.text(sql_text + f" and word_type = 1 and word_scope != 999 and '{problem}' ~ problem;")
# ):
# return sql_text + f" and word_type = 1 and word_scope != 999 and '{problem}' ~ problem;"
# return None
sql = query.filter(word_type=1).sql() + " and POSITION(problem in $1) > 0"
data_list = await db.execute_query_dict(sql, [problem])
if data_list:
return [cls(**data) for data in data_list]
# 正则
sql = (
query.filter(word_type=2, word_scope__not=999).sql() + " and $1 ~ problem;"
)
data_list = await db.execute_query_dict(sql, [problem])
if data_list:
return [cls(**data) for data in data_list]
return None
@classmethod
async def get_answer(
@@ -296,26 +289,16 @@ class WordBank(db.Model):
:param word_scope: 词条范围
:param word_type: 词条类型
"""
query = await cls.check(event, problem, word_scope, word_type)
if query is not None:
if isinstance(query, str):
answer_list = await db.all(db.text(query), problem=problem)
answer = random.choice(answer_list)
return (
await cls._format2answer(answer[6], answer[7], answer[1], answer[2])
if answer.placeholder
else answer.answer
)
else:
answer_list = await query.gino.all()
answer = random.choice(answer_list)
return (
await cls._format2answer(
problem, answer.answer, answer.user_qq, answer.group_id
)
if answer.placeholder
else answer.answer
data_list = await cls.check_problem(event, problem, word_scope, word_type)
if data_list:
answer = random.choice(data_list)
return (
await cls._format2answer(
problem, answer.answer, answer.user_qq, answer.group_id
)
if answer.placeholder
else answer.answer
)
@classmethod
async def get_problem_all_answer(
@@ -336,22 +319,14 @@ class WordBank(db.Model):
"""
if index is not None:
if group_id:
problem = (await cls.query.where(cls.group_id == group_id).gino.all())[
index
]
problem_ = (await cls.filter(group_id=group_id).all())[index]
else:
problem = (
await cls.query.where(
cls.word_scope == (word_scope or 0)
).gino.all()
)[index]
problem = problem.problem
answer = cls.query.where(cls.problem == problem)
problem_ = (await cls.filter(word_scope=(word_scope or 0)).all())[index]
problem = problem_.problem
answer = cls.filter(problem=problem)
if group_id:
answer = answer.where(cls.group_id == group_id)
return [
await cls._format2answer("", "", 0, 0, x) for x in (await answer.gino.all())
]
answer = answer.filter(group_id=group_id)
return [await cls._format2answer("", "", 0, 0, x) for x in (await answer.all())]
@classmethod
async def delete_group_problem(
@@ -373,23 +348,17 @@ class WordBank(db.Model):
if await cls.exists(None, group_id, problem, None, word_scope):
if index is not None:
if group_id:
query = await cls.query.where(
(cls.group_id == group_id) & (cls.problem == problem)
).gino.all()
query = await cls.filter(group_id=group_id, problem=problem).all()
else:
query = await cls.query.where(
(cls.word_scope == 0) & (cls.problem == problem)
).gino.all()
query = await cls.filter(word_scope=0, problem=problem).all()
await query[index].delete()
else:
if group_id:
await WordBank.delete.where(
(cls.group_id == group_id) & (cls.problem == problem)
).gino.status()
await WordBank.filter(group_id=group_id, problem=problem).delete()
else:
await WordBank.delete.where(
(cls.word_scope == word_scope) & (cls.problem == problem)
).gino.status()
await WordBank.filter(
word_scope=word_scope, problem=problem
).delete()
return True
return False
@@ -414,23 +383,20 @@ class WordBank(db.Model):
"""
if index is not None:
if group_id:
query = await cls.query.where(
(cls.group_id == group_id) & (cls.problem == problem)
).gino.all()
query = await cls.filter(group_id=group_id, problem=problem).all()
else:
query = await cls.query.where(
(cls.word_scope == word_scope) & (cls.problem == problem)
).gino.all()
await query[index].update(problem=replace_str).apply()
query = await cls.filter(word_scope=word_scope, problem=problem).all()
query[index].problem = replace_str
await query[index].save(update_fields=["problem"])
else:
if group_id:
await WordBank.update.values(problem=replace_str).where(
(cls.group_id == group_id) & (cls.problem == problem)
).gino.status()
await cls.filter(group_id=group_id, problem=problem).update(
problem=replace_str
)
else:
await WordBank.update.values(problem=replace_str).where(
(cls.word_scope == word_scope) & (cls.problem == problem)
).gino.status()
await cls.filter(word_scope=word_scope, problem=problem).update(
problem=replace_str
)
@classmethod
async def get_group_all_problem(
@@ -443,7 +409,7 @@ class WordBank(db.Model):
:param group_id: 群号
"""
return cls._handle_problem(
await cls.query.where(cls.group_id == group_id).gino.all()
await cls.filter(group_id=group_id).all() # type: ignore
)
@classmethod
@@ -455,7 +421,7 @@ class WordBank(db.Model):
:param word_scope: 词条范围
"""
return cls._handle_problem(
await cls.query.where(cls.word_scope == word_scope).gino.all()
await cls.filter(word_scope=word_scope).all() # type: ignore
)
@classmethod
@@ -467,13 +433,13 @@ class WordBank(db.Model):
:param word_type: 词条类型
"""
return cls._handle_problem(
await cls.query.where(cls.word_type == word_type).gino.all()
await cls.filter(word_type=word_type).all() # type: ignore
)
@classmethod
def _handle_problem(cls, msg_list: List[Union[str, MessageSegment]]):
def _handle_problem(cls, msg_list: List["WordBank"]):
"""
说明:
说明:
格式化处理问题
参数:
:param msg_list: 消息列表
@@ -514,7 +480,9 @@ class WordBank(db.Model):
word_scope = 0
word_type = 0
# 对图片做额外处理
if not await cls.exists(user_id, group_id, problem, answer, word_scope, word_type):
if not await cls.exists(
user_id, group_id, problem, answer, word_scope, word_type
):
await cls.create(
user_qq=user_id,
group_id=group_id,
-20
View File
@@ -1,20 +0,0 @@
from services.db_context import db
from typing import List
class WordBank(db.Model):
__tablename__ = "word_bank"
user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.Integer())
search_type = db.Column(db.Integer(), nullable=False, default=0)
problem = db.Column(db.String(), nullable=False)
answer = db.Column(db.String(), nullable=False)
format = db.Column(db.String())
create_time = db.Column(db.DateTime(), nullable=False)
update_time = db.Column(db.DateTime(), nullable=False)
@classmethod
async def get_all(cls) -> List['WordBank']:
return await cls.query.gino.all()
+16 -11
View File
@@ -1,14 +1,15 @@
import imagehash
from PIL import Image
from io import BytesIO
from services.log import logger
import imagehash
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11 import MessageEvent, Bot
from PIL import Image
from utils.utils import get_message_text, get_message_img, get_message_at
from ._model import WordBank
from services.log import logger
from utils.http_utils import AsyncHttpx
from utils.utils import get_message_at, get_message_img, get_message_text
from ._model import WordBank
async def check(bot: Bot, event: MessageEvent, state: T_State) -> bool:
@@ -23,11 +24,11 @@ async def check(bot: Bot, event: MessageEvent, state: T_State) -> bool:
except Exception as e:
logger.warning(f"word_bank rule 获取图片失败 {type(e)}:{e}")
if at:
temp = ''
temp = ""
for seg in event.message:
if seg.type == 'at':
if seg.type == "at":
temp += f"[at:{seg.data['qq']}]"
elif seg.type == 'text':
elif seg.type == "text":
temp += seg.data["text"]
problem = temp
if event.to_me and bot.config.nickname:
@@ -35,9 +36,13 @@ async def check(bot: Bot, event: MessageEvent, state: T_State) -> bool:
problem = f"[at:{bot.self_id}]" + problem
else:
if problem and bot.config.nickname:
nickname = [nk for nk in bot.config.nickname if str(event.original_message).startswith(nk)]
nickname = [
nk
for nk in bot.config.nickname
if str(event.original_message).startswith(nk)
]
problem = nickname[0] + problem if nickname else problem
if problem and (await WordBank.check(event, problem) is not None):
if problem and (await WordBank.check_problem(event, problem) is not None):
state["problem"] = problem
return True
return False
+19 -11
View File
@@ -1,21 +1,29 @@
import re
from typing import Tuple, Any, Optional
from typing import Any, Optional, Tuple
from nonebot import on_command, on_regex
from nonebot.adapters.onebot.v11 import (
Bot,
GroupMessageEvent,
Message,
MessageEvent,
PrivateMessageEvent,
unescape,
)
from nonebot.exception import FinishedException
from nonebot.internal.params import Arg, ArgStr
from nonebot.params import Command, CommandArg, RegexGroup
from nonebot.typing import T_State
from utils.utils import get_message_at, is_number, get_message_img
from nonebot.params import CommandArg, RegexGroup, Command
from nonebot.exception import FinishedException
from services.log import logger
from configs.path_config import DATA_PATH
from utils.message_builder import custom_forward_msg
from ._model import WordBank
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent, PrivateMessageEvent, unescape
from nonebot import on_command, on_regex
from configs.config import Config
from ._data_source import delete_word, update_word, show_word
from configs.path_config import DATA_PATH
from services.log import logger
from utils.message_builder import custom_forward_msg
from utils.utils import get_message_at, get_message_img, is_number
from ._config import scope2int, type2int
from ._data_source import delete_word, show_word, update_word
from ._model import WordBank
__zx_plugin_name__ = "词库问答 [Admin]"
__plugin_usage__ = r"""
+15 -15
View File
@@ -1,21 +1,23 @@
import asyncio
import os
import random
import jieba.analyse
import re
from typing import List
from PIL import Image as IMG
import jieba
from emoji import replace_emoji # type: ignore
from wordcloud import WordCloud, ImageColorGenerator
import numpy as np
import matplotlib.pyplot as plt
from io import BytesIO
from configs.path_config import IMAGE_PATH, FONT_PATH
from typing import List
import jieba
import jieba.analyse
import matplotlib.pyplot as plt
import numpy as np
from emoji import replace_emoji # type: ignore
from PIL import Image as IMG
from wordcloud import ImageColorGenerator, WordCloud
from configs.config import Config
from configs.path_config import FONT_PATH, IMAGE_PATH
from models.chat_history import ChatHistory
from services import logger
from utils.http_utils import AsyncHttpx
from models.chat_history import ChatHistory
from configs.config import Config
async def pre_precess(msg: List[str], config) -> str:
@@ -117,10 +119,8 @@ async def draw_word_cloud(messages, config):
async def get_list_msg(user_id, group_id, days):
messages_list = (
await ChatHistory()
._get_msg(uid=user_id, gid=group_id, type_="group", days=days)
.gino.all()
messages_list = await ChatHistory().get_message(
uid=user_id, gid=group_id, type_="group", days=days
)
if messages_list:
messages = [i.text for i in messages_list]