mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-29 00:32:06 +08:00
refactor code
This commit is contained in:
+3
-18
@@ -1,11 +1,8 @@
|
||||
from typing import Optional
|
||||
import shutil
|
||||
from nonebot.log import logger
|
||||
from playwright.async_api import Browser, async_playwright
|
||||
import nonebot
|
||||
from nonebot import Driver
|
||||
from appdirs import AppDirs
|
||||
from pathlib import Path
|
||||
from services.log import logger
|
||||
|
||||
|
||||
@@ -22,7 +19,7 @@ async def init(**kwargs) -> Optional[Browser]:
|
||||
_browser = await browser.chromium.launch(**kwargs)
|
||||
return _browser
|
||||
except NotImplementedError:
|
||||
logger.warning('win环境下 初始化playwright失败....请替换环境至linux')
|
||||
logger.warning("win环境下 初始化playwright失败....请替换环境至linux")
|
||||
return None
|
||||
|
||||
|
||||
@@ -36,18 +33,6 @@ def install():
|
||||
logger.info("正在检查 Chromium 更新")
|
||||
import sys
|
||||
from playwright.__main__ import main
|
||||
sys.argv = ['', 'install', 'chromium']
|
||||
|
||||
sys.argv = ["", "install", "chromium"]
|
||||
main()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
def delete_pyppeteer():
|
||||
"""删除 Pyppeteer 遗留的 Chromium"""
|
||||
|
||||
dir = Path(AppDirs('pyppeteer').user_data_dir)
|
||||
if not dir.exists():
|
||||
return
|
||||
|
||||
shutil.rmtree(dir)
|
||||
logger.info("已清理 Pyppeteer 依赖残留")
|
||||
|
||||
|
||||
+11
-4
@@ -1,9 +1,16 @@
|
||||
from models.group_member_info import GroupInfoUser
|
||||
from typing import List
|
||||
|
||||
|
||||
# 生成通用排行榜
|
||||
async def init_rank(users: list, all_user_data: list, group_id: int):
|
||||
all_user_id = [user.user_qq for user in users]
|
||||
async def init_rank(all_user_id: List[int], all_user_data: List[int], group_id: int) -> str:
|
||||
"""
|
||||
说明:
|
||||
初始化通用的数据排行榜
|
||||
参数:
|
||||
:param all_user_id: 所有用户的qq号
|
||||
:param all_user_data: 所有用户需要排行的对应数据
|
||||
:param group_id: 群号,用于从数据库中获取该用户在此群的昵称
|
||||
"""
|
||||
rst = ''
|
||||
for i in range(len(all_user_id) if len(all_user_id) < 10 else 10):
|
||||
_max = max(all_user_data)
|
||||
@@ -11,7 +18,7 @@ async def init_rank(users: list, all_user_data: list, group_id: int):
|
||||
all_user_id.remove(max_user_id)
|
||||
all_user_data.remove(_max)
|
||||
try:
|
||||
user_name = (await GroupInfoUser.select_member_info(max_user_id, group_id)).user_name
|
||||
user_name = (await GroupInfoUser.get_member_info(max_user_id, group_id)).user_name
|
||||
except AttributeError:
|
||||
user_name = f'{max_user_id}'
|
||||
rst += f'{user_name}: {_max}\n'
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
from configs.path_config import IMAGE_PATH, TTF_PATH
|
||||
from PIL import Image, ImageFile, ImageDraw, ImageFont
|
||||
from imagehash import ImageHash
|
||||
from io import BytesIO
|
||||
from matplotlib import pyplot as plt
|
||||
from typing import Tuple, Optional
|
||||
from pathlib import Path
|
||||
import cv2
|
||||
import base64
|
||||
import imagehash
|
||||
|
||||
|
||||
def compare_image_with_hash(
|
||||
image_file1: str, image_file2: str, max_dif: int = 1.5
|
||||
) -> bool:
|
||||
"""
|
||||
说明:
|
||||
比较两张图片的hash值是否相同
|
||||
参数:
|
||||
:param image_file1: 图片文件路径
|
||||
:param image_file2: 图片文件路径
|
||||
:param max_dif: 允许最大hash差值, 越小越精确,最小为0
|
||||
"""
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
hash_1 = get_img_hash(image_file1)
|
||||
hash_2 = get_img_hash(image_file2)
|
||||
dif = hash_1 - hash_2
|
||||
if dif < 0:
|
||||
dif = -dif
|
||||
if dif <= max_dif:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def get_img_hash(image_file: str) -> ImageHash:
|
||||
"""
|
||||
说明:
|
||||
获取图片的hash值
|
||||
参数:
|
||||
:param image_file: 图片文件路径
|
||||
"""
|
||||
with open(image_file, "rb") as fp:
|
||||
hash_value = imagehash.average_hash(Image.open(fp))
|
||||
return hash_value
|
||||
|
||||
|
||||
def compressed_image(in_file: str, out_file: str = None, ratio: float = 0.9):
|
||||
"""
|
||||
说明:
|
||||
压缩图片
|
||||
参数:
|
||||
:param in_file: 被压缩的文件路径
|
||||
:param out_file: 压缩后输出的文件路径
|
||||
:param ratio: 压缩率,宽高 * 压缩率
|
||||
"""
|
||||
in_file = Path(IMAGE_PATH) / in_file
|
||||
out_file = Path(IMAGE_PATH) / out_file if out_file else in_file
|
||||
h, w, d = cv2.imread(str(in_file.absolute())).shape
|
||||
img = cv2.resize(cv2.imread(str(in_file.absolute())), (int(w * ratio), int(h * ratio)))
|
||||
cv2.imwrite(str(out_file.absolute()), img)
|
||||
|
||||
|
||||
def alpha2white_PIL(pic: Image) -> Image:
|
||||
"""
|
||||
说明:
|
||||
将图片透明背景转化为白色
|
||||
参数:
|
||||
:param pic: 通过PIL打开的图片文件
|
||||
"""
|
||||
img = pic.convert("RGBA")
|
||||
width, height = img.size
|
||||
for yh in range(height):
|
||||
for xw in range(width):
|
||||
dot = (xw, yh)
|
||||
color_d = img.getpixel(dot)
|
||||
if color_d[3] == 0:
|
||||
color_d = (255, 255, 255, 255)
|
||||
img.putpixel(dot, color_d)
|
||||
return img
|
||||
|
||||
|
||||
def pic2b64(pic: Image) -> str:
|
||||
"""
|
||||
说明:
|
||||
PIL图片转base64
|
||||
参数:
|
||||
:param pic: 通过PIL打开的图片文件
|
||||
"""
|
||||
buf = BytesIO()
|
||||
pic.save(buf, format="PNG")
|
||||
base64_str = base64.b64encode(buf.getvalue()).decode()
|
||||
return "base64://" + base64_str
|
||||
|
||||
|
||||
def fig2b64(plt_: plt) -> str:
|
||||
"""
|
||||
说明:
|
||||
matplotlib图片转base64
|
||||
参数:
|
||||
:param plt_: matplotlib生成的图片
|
||||
"""
|
||||
buf = BytesIO()
|
||||
plt_.savefig(buf, format="PNG", dpi=100)
|
||||
base64_str = base64.b64encode(buf.getvalue()).decode()
|
||||
return "base64://" + base64_str
|
||||
|
||||
|
||||
def is_valid(file: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
判断图片是否损坏
|
||||
参数:
|
||||
:param file: 图片文件路径
|
||||
"""
|
||||
valid = True
|
||||
try:
|
||||
Image.open(file).load()
|
||||
except OSError:
|
||||
valid = False
|
||||
return valid
|
||||
|
||||
|
||||
class CreateImg:
|
||||
"""
|
||||
快捷生成图片与操作图片的工具类
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
w,
|
||||
h,
|
||||
paste_image_width=0,
|
||||
paste_image_height=0,
|
||||
color="white",
|
||||
image_type="RGBA",
|
||||
font_size=10,
|
||||
background="",
|
||||
ttf="yz.ttf",
|
||||
ratio=1,
|
||||
):
|
||||
"""
|
||||
参数:
|
||||
:param w: 自定义图片的宽度,w=0时为图片原本宽度
|
||||
:param h: 自定义图片的高度,h=0时为图片原本高度
|
||||
:param paste_image_width: 当图片做为背景图时,设置贴图的宽度,用于贴图自动换行
|
||||
:param paste_image_height: 当图片做为背景图时,设置贴图的高度,用于贴图自动换行
|
||||
:param color: 生成图片的颜色
|
||||
:param image_type: 图片的类型
|
||||
:param font_size: 文字大小
|
||||
:param background: 打开图片的路径
|
||||
:param ttf: 字体,默认在 resource/ttf/ 路径下
|
||||
:param ratio: 倍率压缩
|
||||
"""
|
||||
self.w = int(w)
|
||||
self.h = int(h)
|
||||
self.paste_image_width = int(paste_image_width)
|
||||
self.paste_image_height = int(paste_image_height)
|
||||
self.current_w = 0
|
||||
self.current_h = 0
|
||||
self.ttfont = ImageFont.truetype(TTF_PATH + ttf, int(font_size))
|
||||
if not background:
|
||||
self.markImg = Image.new(image_type, (self.w, self.h), color)
|
||||
else:
|
||||
if not w and not h:
|
||||
self.markImg = Image.open(background)
|
||||
w, h = self.markImg.size
|
||||
if ratio and ratio > 0 and ratio != 1:
|
||||
self.w = int(ratio * w)
|
||||
self.h = int(ratio * h)
|
||||
self.markImg = self.markImg.resize(
|
||||
(self.w, self.h), Image.ANTIALIAS
|
||||
)
|
||||
else:
|
||||
self.w = w
|
||||
self.h = h
|
||||
else:
|
||||
self.markImg = Image.open(background).resize(
|
||||
(self.w, self.h), Image.ANTIALIAS
|
||||
)
|
||||
self.draw = ImageDraw.Draw(self.markImg)
|
||||
self.size = self.w, self.h
|
||||
|
||||
def paste(
|
||||
self,
|
||||
img: "CreateImg" or Image,
|
||||
pos: Tuple[int, int] = None,
|
||||
alpha: bool = False,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
贴图
|
||||
参数:
|
||||
:param img: 已打开的图片文件,可以为 CreateImg 或 Image
|
||||
:param pos: 贴图位置(左上角)
|
||||
:param alpha: 图片背景是否为透明
|
||||
"""
|
||||
if isinstance(img, CreateImg):
|
||||
img = img.markImg
|
||||
if self.current_w == self.w:
|
||||
self.current_w = 0
|
||||
self.current_h += self.paste_image_height
|
||||
if not pos:
|
||||
pos = (self.current_w, self.current_h)
|
||||
if alpha:
|
||||
try:
|
||||
self.markImg.paste(img, pos, img)
|
||||
except ValueError:
|
||||
img = img.convert("RGBA")
|
||||
self.markImg.paste(img, pos, img)
|
||||
else:
|
||||
self.markImg.paste(img, pos)
|
||||
self.current_w += self.paste_image_width
|
||||
|
||||
def getsize(self, msg: str) -> Tuple[int, int]:
|
||||
"""
|
||||
说明:
|
||||
获取文字在该图片 font_size 下所需要的空间
|
||||
参数:
|
||||
:param msg: 文字内容
|
||||
"""
|
||||
return self.ttfont.getsize(msg)
|
||||
|
||||
def text(
|
||||
self, pos: Tuple[int, int], text: str, fill: Tuple[int, int, int] = (0, 0, 0)
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
在图片上添加文字
|
||||
参数:
|
||||
:param pos: 文字位置
|
||||
:param text: 文字内容
|
||||
:param fill: 文字颜色
|
||||
"""
|
||||
self.draw.text(pos, text, fill=fill, font=self.ttfont)
|
||||
|
||||
def save(self, path: str):
|
||||
"""
|
||||
说明:
|
||||
保存图片
|
||||
参数:
|
||||
:param path: 图片路径
|
||||
"""
|
||||
self.markImg.save(path)
|
||||
|
||||
def show(self):
|
||||
"""
|
||||
说明:
|
||||
显示图片
|
||||
"""
|
||||
self.markImg.show(self.markImg)
|
||||
|
||||
def resize(self, ratio: float = 0, w: int = 0, h: int = 0):
|
||||
"""
|
||||
说明:
|
||||
压缩图片
|
||||
参数:
|
||||
:param ratio: 压缩倍率
|
||||
:param w: 压缩图片宽度至 w
|
||||
:param h: 压缩图片高度至 h
|
||||
"""
|
||||
if not w and not h and not ratio:
|
||||
raise Exception("缺少参数...")
|
||||
if not w and not h and ratio:
|
||||
w = int(self.w * ratio)
|
||||
h = int(self.h * ratio)
|
||||
self.markImg = self.markImg.resize((w, h), Image.ANTIALIAS)
|
||||
self.w, self.h = self.markImg.size
|
||||
self.size = self.w, self.h
|
||||
self.draw = ImageDraw.Draw(self.markImg)
|
||||
|
||||
def crop(self, box: Tuple[int, int, int, int]):
|
||||
"""
|
||||
说明:
|
||||
裁剪图片
|
||||
参数:
|
||||
:param box: 左上角坐标,右下角坐标 (left, upper, right, lower)
|
||||
"""
|
||||
self.markImg = self.markImg.crop(box)
|
||||
self.w, self.h = self.markImg.size
|
||||
self.size = self.w, self.h
|
||||
self.draw = ImageDraw.Draw(self.markImg)
|
||||
|
||||
def check_font_size(self, word: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检查文本所需宽度是否大于图片宽度
|
||||
:param word: 文本内容
|
||||
"""
|
||||
return self.ttfont.getsize(word)[0] > self.w
|
||||
|
||||
def transparent(self, n: int = 0):
|
||||
"""
|
||||
说明:
|
||||
图片透明化
|
||||
参数:
|
||||
:param n: 透明化大小内边距
|
||||
"""
|
||||
self.markImg = self.markImg.convert("RGBA")
|
||||
x, y = self.markImg.size
|
||||
for i in range(n, x - n):
|
||||
for k in range(n, y - n):
|
||||
color = self.markImg.getpixel((i, k))
|
||||
color = color[:-1] + (100,)
|
||||
self.markImg.putpixel((i, k), color)
|
||||
|
||||
def pic2bs4(self) -> str:
|
||||
"""
|
||||
说明:
|
||||
CreateImg 转 base64
|
||||
"""
|
||||
buf = BytesIO()
|
||||
self.markImg.save(buf, format="PNG")
|
||||
base64_str = base64.b64encode(buf.getvalue()).decode()
|
||||
return base64_str
|
||||
|
||||
def convert(self, type_: str):
|
||||
"""
|
||||
说明:
|
||||
修改图片类型
|
||||
参数:
|
||||
:param type_: 类型
|
||||
"""
|
||||
self.markImg = self.markImg.convert(type_)
|
||||
|
||||
def rectangle(
|
||||
self,
|
||||
xy: Tuple[int, int, int, int],
|
||||
fill: Optional[Tuple[int, int, int]] = None,
|
||||
outline: str = None,
|
||||
width: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
画框
|
||||
参数:
|
||||
:param xy: 坐标
|
||||
:param fill: 填充颜色
|
||||
:param outline: 轮廓颜色
|
||||
:param width: 线宽
|
||||
"""
|
||||
self.draw.rectangle(xy, fill, outline, width)
|
||||
|
||||
def line(
|
||||
self,
|
||||
xy: Tuple[int, int, int, int],
|
||||
fill: Optional[Tuple[int, int, int]] = None,
|
||||
width: int = 1,
|
||||
):
|
||||
"""
|
||||
说明:
|
||||
画线
|
||||
参数:
|
||||
:param xy: 坐标
|
||||
:param fill: 填充
|
||||
:param width: 线宽
|
||||
"""
|
||||
self.draw.line(xy, fill, width)
|
||||
|
||||
def circle(self):
|
||||
"""
|
||||
说明:
|
||||
将 CreateImg 图片变为圆形
|
||||
"""
|
||||
self.convert("RGBA")
|
||||
r2 = min(self.w, self.h)
|
||||
if self.w != self.h:
|
||||
self.resize(w=r2, h=r2)
|
||||
r3 = int(r2 / 2)
|
||||
imb = Image.new("RGBA", (r3 * 2, r3 * 2), (255, 255, 255, 0))
|
||||
pim_a = self.markImg.load() # 像素的访问对象
|
||||
pim_b = imb.load()
|
||||
r = float(r2 / 2)
|
||||
for i in range(r2):
|
||||
for j in range(r2):
|
||||
lx = abs(i - r) # 到圆心距离的横坐标
|
||||
ly = abs(j - r) # 到圆心距离的纵坐标
|
||||
l = (pow(lx, 2) + pow(ly, 2)) ** 0.5 # 三角函数 半径
|
||||
if l < r3:
|
||||
pim_b[i - (r - r3), j - (r - r3)] = pim_a[i, j]
|
||||
self.markImg = imb
|
||||
|
||||
#
|
||||
def getchannel(self, itype):
|
||||
self.markImg = self.markImg.getchannel(itype)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
@@ -1,339 +0,0 @@
|
||||
import os
|
||||
from configs.path_config import IMAGE_PATH, TXT_PATH, TTF_PATH
|
||||
from PIL import Image, ImageFile, ImageDraw, ImageFont
|
||||
import cv2
|
||||
from typing import Tuple
|
||||
import imagehash
|
||||
import base64
|
||||
from io import BytesIO
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
|
||||
# 扫描图库id是否连贯
|
||||
def scan_img(path):
|
||||
path = IMAGE_PATH + path
|
||||
nolist = []
|
||||
length = len(os.listdir(path))
|
||||
print(length)
|
||||
for i in range(length):
|
||||
if i in nolist:
|
||||
continue
|
||||
img_path = path + "{}.jpg".format(i)
|
||||
if not os.path.exists(img_path):
|
||||
print("不存在=== " + str(length) + ".jpg -------> " + str(i) + ".jpg")
|
||||
os.rename(path + "{}.jpg".format(length - 1), img_path)
|
||||
nolist.append(length)
|
||||
length -= 1
|
||||
|
||||
|
||||
# 比较hash值
|
||||
def compare_image_with_hash(image_file1, image_file2, max_dif=1.5):
|
||||
"""
|
||||
max_dif: 允许最大hash差值, 越小越精确,最小为0
|
||||
推荐使用
|
||||
"""
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
hash_1 = None
|
||||
hash_2 = None
|
||||
hash_1 = get_img_hash(image_file1)
|
||||
hash_2 = get_img_hash(image_file2)
|
||||
dif = hash_1 - hash_2
|
||||
if dif < 0:
|
||||
dif = -dif
|
||||
if dif <= max_dif:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
# 比较图片与hash值
|
||||
def compare_one_img_hash(image_file, hash_2, max_dif=1.5):
|
||||
hash_1 = get_img_hash(image_file)
|
||||
dif = hash_1 - hash_2
|
||||
if dif < 0:
|
||||
dif = -dif
|
||||
if dif <= max_dif:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def get_img_hash(image_file):
|
||||
with open(image_file, 'rb') as fp:
|
||||
hash_value = imagehash.average_hash(Image.open(fp))
|
||||
return hash_value
|
||||
|
||||
|
||||
# 压缩图片
|
||||
def rar_imgs(inpath, outpath, ratio=0.9, start=0, end=0, lens=0, maxsize=0.0, in_file_name='', out_file_name='',
|
||||
itype='jpg'):
|
||||
in_path = IMAGE_PATH + inpath + '/'
|
||||
out_path = IMAGE_PATH + outpath + '/'
|
||||
# scan_img(inpath)
|
||||
l = []
|
||||
if in_file_name != '' and out_file_name != '':
|
||||
filein = in_path + in_file_name + "." + itype
|
||||
fileout = out_path + out_file_name + "." + itype
|
||||
h, w, d = cv2.imread(filein).shape
|
||||
width = int(w * ratio)
|
||||
height = int(h * ratio)
|
||||
ResizeImage(filein, fileout, width, height)
|
||||
else:
|
||||
if lens == 0:
|
||||
lens = len(os.listdir(in_path))
|
||||
if end == 0:
|
||||
end = lens
|
||||
for i in range(start, end):
|
||||
if i in l:
|
||||
continue
|
||||
if maxsize != 0:
|
||||
if os.path.getsize(in_path + str(i) + ".jpg") > maxsize:
|
||||
print("压缩----->", i, ".jpg")
|
||||
filein = in_path + str(i) + ".jpg"
|
||||
fileout = out_path + str(i) + ".jpg"
|
||||
h, w, d = cv2.imread(filein).shape
|
||||
width = int(w * ratio)
|
||||
height = int(h * ratio)
|
||||
ResizeImage(filein, fileout, width, height)
|
||||
else:
|
||||
continue
|
||||
else:
|
||||
print("压缩----->", i, ".jpg")
|
||||
filein = in_path + str(i) + ".jpg"
|
||||
fileout = out_path + str(i) + ".jpg"
|
||||
h, w, d = cv2.imread(filein).shape
|
||||
width = int(w * ratio)
|
||||
height = int(h * ratio)
|
||||
ResizeImage(filein, fileout, width, height)
|
||||
|
||||
|
||||
# 压缩
|
||||
def ResizeImage(filein, fileout, width, height):
|
||||
img = cv2.resize(cv2.imread(filein), (int(width), int(height)))
|
||||
cv2.imwrite(fileout, img)
|
||||
|
||||
|
||||
# 保存图片压缩后的hash值
|
||||
def save_img_hash(path, name):
|
||||
for file in os.listdir(IMAGE_PATH + path):
|
||||
if os.path.getsize(IMAGE_PATH + path + file) > 1024 * 1024 * 1.5:
|
||||
compare_img_hash_in_txt(IMAGE_PATH + 'rar/' + file, name)
|
||||
else:
|
||||
compare_img_hash_in_txt(IMAGE_PATH + path + file, name)
|
||||
|
||||
|
||||
# 比较色图hash值
|
||||
def compare_img_hash_in_txt(file, name, mode=1):
|
||||
with open(TXT_PATH + name + ".txt", 'a+') as txtfile:
|
||||
txtfile.seek(0)
|
||||
hash_list = txtfile.read()[:-1].strip(",")
|
||||
txtfile.seek(2)
|
||||
with open(file, 'rb') as fp:
|
||||
img_hash = str(imagehash.average_hash(Image.open(fp)))
|
||||
if img_hash not in hash_list:
|
||||
if mode == 1:
|
||||
txtfile.write(img_hash + ",")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# 透明背景 -> 白色
|
||||
def alphabg2white_PIL(img):
|
||||
img = img.convert('RGBA')
|
||||
sp = img.size
|
||||
width = sp[0]
|
||||
height = sp[1]
|
||||
for yh in range(height):
|
||||
for xw in range(width):
|
||||
dot = (xw, yh)
|
||||
color_d = img.getpixel(dot)
|
||||
if color_d[3] == 0:
|
||||
color_d = (255, 255, 255, 255)
|
||||
img.putpixel(dot, color_d)
|
||||
return img
|
||||
|
||||
|
||||
def pic2b64(pic: Image) -> str:
|
||||
buf = BytesIO()
|
||||
pic.save(buf, format='PNG')
|
||||
base64_str = base64.b64encode(buf.getvalue()).decode()
|
||||
return 'base64://' + base64_str
|
||||
|
||||
|
||||
def fig2b64(plt: plt) -> str:
|
||||
buf = BytesIO()
|
||||
plt.savefig(buf, format='PNG', dpi=100)
|
||||
base64_str = base64.b64encode(buf.getvalue()).decode()
|
||||
return 'base64://' + base64_str
|
||||
|
||||
|
||||
class CreateImg:
|
||||
def __init__(self,
|
||||
w,
|
||||
h,
|
||||
img_w=0,
|
||||
img_h=0,
|
||||
color='white',
|
||||
image_type='RGBA',
|
||||
font_size=10,
|
||||
background='',
|
||||
ttf='yz.ttf',
|
||||
divisor=1):
|
||||
self.w = int(w)
|
||||
self.h = int(h)
|
||||
self.img_w = int(img_w)
|
||||
self.img_h = int(img_h)
|
||||
self.current_w = 0
|
||||
self.current_h = 0
|
||||
self.ttfont = ImageFont.truetype(TTF_PATH + ttf, int(font_size))
|
||||
if not background:
|
||||
self.markImg = Image.new(image_type, (self.w, self.h), color)
|
||||
else:
|
||||
if w == 0 and h == 0:
|
||||
self.markImg = Image.open(background)
|
||||
w, h = self.markImg.size
|
||||
if divisor:
|
||||
self.w = int(divisor * w)
|
||||
self.h = int(divisor * h)
|
||||
self.markImg = self.markImg.resize((self.w, self.h), Image.ANTIALIAS)
|
||||
else:
|
||||
self.w = w
|
||||
self.h = h
|
||||
else:
|
||||
self.markImg = Image.open(background).resize((self.w, self.h), Image.ANTIALIAS)
|
||||
self.draw = ImageDraw.Draw(self.markImg)
|
||||
self.size = self.w, self.h
|
||||
|
||||
# 贴图
|
||||
def paste(self, img, pos=None, alpha=False):
|
||||
if isinstance(img, CreateImg):
|
||||
img = img.markImg
|
||||
if self.current_w == self.w:
|
||||
self.current_w = 0
|
||||
self.current_h += self.img_h
|
||||
if not pos:
|
||||
pos = (self.current_w, self.current_h)
|
||||
if alpha:
|
||||
try:
|
||||
self.markImg.paste(img, pos, img)
|
||||
except ValueError:
|
||||
img = img.convert("RGBA")
|
||||
self.markImg.paste(img, pos, img)
|
||||
else:
|
||||
self.markImg.paste(img, pos)
|
||||
self.current_w += self.img_w
|
||||
return self.markImg
|
||||
|
||||
def crop(self, box: Tuple[int, int, int, int]):
|
||||
"""
|
||||
说明:
|
||||
裁剪图片
|
||||
参数:
|
||||
:param box: 左上角坐标,右下角坐标 (left, upper, right, lower)
|
||||
"""
|
||||
self.markImg = self.markImg.crop(box)
|
||||
self.w, self.h = self.markImg.size
|
||||
self.size = self.w, self.h
|
||||
self.draw = ImageDraw.Draw(self.markImg)
|
||||
|
||||
# 获取文字大小
|
||||
def getsize(self, msg):
|
||||
return self.ttfont.getsize(msg)
|
||||
|
||||
# 写字
|
||||
def text(self, pos, text, fill=(0, 0, 0)):
|
||||
self.draw.text(pos, text, fill=fill, font=self.ttfont)
|
||||
return self.markImg
|
||||
|
||||
# 饼图
|
||||
def pieslice(self):
|
||||
self.draw.pieslice((350, 50, 500, 200), -150, -30, 'pink', 'crimson')
|
||||
return self.markImg
|
||||
|
||||
# 保存
|
||||
def save(self, path):
|
||||
self.markImg.save(path)
|
||||
|
||||
# 显示
|
||||
def show(self):
|
||||
self.markImg.show(self.markImg)
|
||||
|
||||
# 压缩
|
||||
def resize(self, ratio=0, w=0, h=0):
|
||||
if not w and not h and not ratio:
|
||||
raise Exception('缺少参数...')
|
||||
if not w and not h and ratio:
|
||||
w = int(self.w * ratio)
|
||||
h = int(self.h * ratio)
|
||||
self.markImg = self.markImg.resize((w, h), Image.ANTIALIAS)
|
||||
self.w, self.h = self.markImg.size
|
||||
self.size = self.w, self.h
|
||||
self.draw = ImageDraw.Draw(self.markImg)
|
||||
|
||||
# 检查字体大小
|
||||
def check_font_size(self, word):
|
||||
return self.ttfont.getsize(word)[0] > self.w
|
||||
|
||||
# 透明化
|
||||
def transparent(self, n=0):
|
||||
self.markImg = self.markImg.convert('RGBA') # 修改颜色通道为RGBA
|
||||
x, y = self.markImg.size # 获得长和宽
|
||||
# 设置每个像素点颜色的透明度
|
||||
for i in range(n, x - n):
|
||||
for k in range(n, y - n):
|
||||
color = self.markImg.getpixel((i, k))
|
||||
color = color[:-1] + (100, )
|
||||
self.markImg.putpixel((i, k), color)
|
||||
return self.markImg
|
||||
|
||||
# 转bs4:
|
||||
def pic2bs4(self):
|
||||
buf = BytesIO()
|
||||
self.markImg.save(buf, format='PNG')
|
||||
base64_str = base64.b64encode(buf.getvalue()).decode()
|
||||
return base64_str
|
||||
|
||||
#
|
||||
def convert(self, itype):
|
||||
self.markImg = self.markImg.convert(itype)
|
||||
|
||||
# 变圆
|
||||
def circle(self):
|
||||
self.convert('RGBA')
|
||||
r2 = min(self.w, self.h)
|
||||
if self.w != self.h:
|
||||
self.resize(w=r2, h=r2)
|
||||
r3 = int(r2 / 2)
|
||||
imb = Image.new('RGBA', (r3 * 2, r3 * 2), (255, 255, 255, 0))
|
||||
pima = self.markImg.load() # 像素的访问对象
|
||||
pimb = imb.load()
|
||||
r = float(r2 / 2)
|
||||
for i in range(r2):
|
||||
for j in range(r2):
|
||||
lx = abs(i - r) # 到圆心距离的横坐标
|
||||
ly = abs(j - r) # 到圆心距离的纵坐标
|
||||
l = (pow(lx, 2) + pow(ly, 2)) ** 0.5 # 三角函数 半径
|
||||
if l < r3:
|
||||
pimb[i - (r - r3), j - (r - r3)] = pima[i, j]
|
||||
self.markImg = imb
|
||||
|
||||
#
|
||||
def getchannel(self, itype):
|
||||
self.markImg = self.markImg.getchannel(itype)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
from configs.path_config import IMAGE_PATH, VOICE_PATH
|
||||
from nonebot.adapters.cqhttp.message import MessageSegment
|
||||
import os
|
||||
from services.log import logger
|
||||
import ujson
|
||||
|
||||
|
||||
def image(img_name: str = None, path: str = '', abspath: str = None, b64: str = None):
|
||||
if abspath:
|
||||
if os.path.exists(abspath):
|
||||
return MessageSegment.image("file:///" + abspath)
|
||||
else:
|
||||
return ''
|
||||
elif b64:
|
||||
if b64.find('base64://') != -1:
|
||||
return MessageSegment.image(b64)
|
||||
else:
|
||||
return MessageSegment.image('base64://' + b64)
|
||||
else:
|
||||
img_name = str(img_name)
|
||||
if img_name.find('http') == -1:
|
||||
if len(img_name.split('.')) == 1:
|
||||
img_name += '.jpg'
|
||||
if os.path.exists(IMAGE_PATH + path + '/' + img_name):
|
||||
return MessageSegment.image("file:///" + IMAGE_PATH + path + '/' + img_name)
|
||||
else:
|
||||
logger.warning(f"图片 {path}/{img_name}缺失.")
|
||||
return ''
|
||||
else:
|
||||
return MessageSegment.image(img_name)
|
||||
|
||||
|
||||
def at(qq):
|
||||
return MessageSegment.at(qq)
|
||||
|
||||
|
||||
def record(voice_name='', path=''):
|
||||
if len(voice_name.split('.')) == 1:
|
||||
voice_name += '.mp3'
|
||||
if path == "":
|
||||
name = VOICE_PATH + "{}.".format(voice_name)
|
||||
else:
|
||||
name = VOICE_PATH + "{}/{}".format(path, voice_name)
|
||||
if voice_name.find('http') == -1:
|
||||
if os.path.exists(name):
|
||||
result = MessageSegment.record("file:///" + name)
|
||||
return result
|
||||
else:
|
||||
logger.warning(f"语音{path}/{voice_name}缺失...")
|
||||
return ""
|
||||
else:
|
||||
return MessageSegment.record(voice_name)
|
||||
|
||||
|
||||
def text(msg):
|
||||
return MessageSegment.text(msg)
|
||||
|
||||
|
||||
def contact_user(qq):
|
||||
return MessageSegment.contact_user(qq)
|
||||
|
||||
|
||||
def share(url, title, content='', image_url=''):
|
||||
return MessageSegment.share(url, title, content, image_url)
|
||||
|
||||
|
||||
def xml(data):
|
||||
return MessageSegment.xml(data)
|
||||
|
||||
|
||||
def json(data):
|
||||
data = ujson.dumps(data)
|
||||
return MessageSegment.json(data)
|
||||
|
||||
|
||||
def face(id_):
|
||||
return MessageSegment.face(id_)
|
||||
|
||||
|
||||
def poke(qq):
|
||||
return MessageSegment('poke', {"qq": qq})
|
||||
|
||||
|
||||
def forward():
|
||||
return MessageSegment.forward()
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# print(get_record_result("dadada", "", type="amr"))
|
||||
@@ -0,0 +1,151 @@
|
||||
from configs.path_config import IMAGE_PATH, VOICE_PATH
|
||||
from nonebot.adapters.cqhttp.message import MessageSegment
|
||||
from services.log import logger
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
import os
|
||||
import ujson
|
||||
|
||||
|
||||
def image(
|
||||
img_name: str = None, path: str = None, abspath: str = None, b64: str = None
|
||||
) -> MessageSegment or str:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.image 消息
|
||||
生成顺序:绝对路径(abspath) > base64(b64) > img_name
|
||||
参数:
|
||||
:param img_name: 图片文件名称,默认在 resource/img 目录下
|
||||
:param path: 图片所在路径,默认在 resource/img 目录下
|
||||
:param abspath: 图片绝对路径
|
||||
:param b64: 图片base64
|
||||
"""
|
||||
if abspath:
|
||||
return (
|
||||
MessageSegment.image("file:///" + abspath)
|
||||
if os.path.exists(abspath)
|
||||
else ""
|
||||
)
|
||||
elif b64:
|
||||
return MessageSegment.image(b64 if "base64://" in b64 else "base64://" + b64)
|
||||
else:
|
||||
if "http" in img_name:
|
||||
return MessageSegment.image(img_name)
|
||||
if len(img_name.split(".")) == 1:
|
||||
img_name += ".jpg"
|
||||
file = (
|
||||
Path(IMAGE_PATH) / path / img_name if path else Path(IMAGE_PATH) / img_name
|
||||
)
|
||||
if file.exists():
|
||||
return MessageSegment.image(f"file:///{file.absolute()}")
|
||||
else:
|
||||
logger.warning(f"图片 {file.absolute()}缺失...")
|
||||
return ""
|
||||
|
||||
|
||||
def at(qq: int) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.at 消息
|
||||
参数:
|
||||
:param qq: qq号
|
||||
"""
|
||||
return MessageSegment.at(qq)
|
||||
|
||||
|
||||
def record(voice_name: str, path: str = None) -> MessageSegment or str:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.record 消息
|
||||
参数:
|
||||
:param voice_name: 音频文件名称,默认在 resource/voice 目录下
|
||||
:param path: 音频文件路径,默认在 resource/voice 目录下
|
||||
"""
|
||||
if len(voice_name.split(".")) == 1:
|
||||
voice_name += ".mp3"
|
||||
file = (
|
||||
Path(VOICE_PATH) / path / voice_name if path else Path(VOICE_PATH) / voice_name
|
||||
)
|
||||
if "http" in voice_name:
|
||||
return MessageSegment.record(voice_name)
|
||||
if file.exists():
|
||||
result = MessageSegment.record(f"file:///{file.absolute()}")
|
||||
return result
|
||||
else:
|
||||
logger.warning(f"语音{file.absolute()}缺失...")
|
||||
return ""
|
||||
|
||||
|
||||
def text(msg: str) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.text 消息
|
||||
参数:
|
||||
:param msg: 消息文本
|
||||
"""
|
||||
return MessageSegment.text(msg)
|
||||
|
||||
|
||||
def contact_user(qq: int) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.contact_user 消息
|
||||
参数:
|
||||
:param qq: qq号
|
||||
"""
|
||||
return MessageSegment.contact_user(qq)
|
||||
|
||||
|
||||
def share(
|
||||
url: str, title: str, content: str = None, image_url: str = None
|
||||
) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.share 消息
|
||||
参数:
|
||||
:param url: 自定义分享的链接
|
||||
:param title: 自定义分享的包体
|
||||
:param content: 自定义分享的内容
|
||||
:param image_url: 自定义分享的展示图片
|
||||
"""
|
||||
return MessageSegment.share(url, title, content, image_url)
|
||||
|
||||
|
||||
def xml(data: str) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.xml 消息
|
||||
参数:
|
||||
:param data: 数据文本
|
||||
"""
|
||||
return MessageSegment.xml(data)
|
||||
|
||||
|
||||
def json(data: str) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.json 消息
|
||||
参数:
|
||||
:param data: 消息数据
|
||||
"""
|
||||
return MessageSegment.json(data)
|
||||
|
||||
|
||||
def face(id_: int) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.face 消息
|
||||
参数:
|
||||
:param id_: 表情id
|
||||
"""
|
||||
return MessageSegment.face(id_)
|
||||
|
||||
|
||||
def poke(qq: int) -> MessageSegment:
|
||||
"""
|
||||
说明:
|
||||
生成一个 MessageSegment.poke 消息
|
||||
参数:
|
||||
:param qq: qq号
|
||||
"""
|
||||
return MessageSegment("poke", {"qq": qq})
|
||||
+2
-2
@@ -39,9 +39,9 @@ user_agent = [
|
||||
"Openwave/ UCWEB7.0.2.37/28/999",
|
||||
"Mozilla/4.0 (compatible; MSIE 6.0; ) Opera/UCWEB7.0.2.37/28/999",
|
||||
# iPhone 6:
|
||||
"Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25"
|
||||
"Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25",
|
||||
]
|
||||
|
||||
|
||||
def get_user_agent():
|
||||
return {'User-Agent': random.choice(user_agent)}
|
||||
return {"User-Agent": random.choice(user_agent)}
|
||||
|
||||
+175
-103
@@ -1,104 +1,128 @@
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from collections import defaultdict
|
||||
from nonebot import require
|
||||
import nonebot
|
||||
import json
|
||||
import pytz
|
||||
from configs.path_config import TXT_PATH
|
||||
from configs.config import system_proxy
|
||||
from configs.config import SYSTEM_PROXY
|
||||
from typing import List, Union
|
||||
from nonebot.adapters import Bot
|
||||
import nonebot
|
||||
import pytz
|
||||
import pypinyin
|
||||
import aiohttp
|
||||
import time
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
scheduler = require('nonebot_plugin_apscheduler').scheduler
|
||||
scheduler = require("nonebot_plugin_apscheduler").scheduler
|
||||
|
||||
|
||||
# 次数检测
|
||||
class CountLimiter:
|
||||
def __init__(self, max):
|
||||
self.count = defaultdict(int)
|
||||
self.max = max
|
||||
"""
|
||||
次数检测工具,检测调用次数是否超过设定值
|
||||
"""
|
||||
|
||||
def add(self, key):
|
||||
def __init__(self, max_count: int):
|
||||
self.count = defaultdict(int)
|
||||
self.max_count = max_count
|
||||
|
||||
def add(self, key: Union[str, int, float]):
|
||||
self.count[key] += 1
|
||||
|
||||
def check(self, key) -> bool:
|
||||
if self.count[key] >= self.max:
|
||||
def check(self, key: Union[str, int, float]) -> bool:
|
||||
if self.count[key] >= self.max_count:
|
||||
self.count[key] = 0
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# 用户正在执行此命令
|
||||
class UserExistLimiter:
|
||||
"""
|
||||
检测用户是否正在调用命令
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.mbool = defaultdict(bool)
|
||||
self.flag_data = defaultdict(bool)
|
||||
self.time = time.time()
|
||||
|
||||
def set_True(self, key):
|
||||
def set_True(self, key: Union[str, int, float]):
|
||||
self.time = time.time()
|
||||
self.mbool[key] = True
|
||||
self.flag_data[key] = True
|
||||
|
||||
def set_False(self, key):
|
||||
self.mbool[key] = False
|
||||
def set_False(self, key: Union[str, int, float]):
|
||||
self.flag_data[key] = False
|
||||
|
||||
def check(self, key):
|
||||
def check(self, key: Union[str, int, float]) -> bool:
|
||||
if time.time() - self.time > 30:
|
||||
self.set_False(key)
|
||||
return False
|
||||
return self.mbool[key]
|
||||
return self.flag_data[key]
|
||||
|
||||
|
||||
# 命令cd
|
||||
class FreqLimiter:
|
||||
def __init__(self, default_cd_seconds):
|
||||
"""
|
||||
命令冷却,检测用户是否处于冷却状态
|
||||
"""
|
||||
|
||||
def __init__(self, default_cd_seconds: int):
|
||||
self.next_time = defaultdict(float)
|
||||
self.default_cd = default_cd_seconds
|
||||
|
||||
def check(self, key) -> bool:
|
||||
def check(self, key: Union[str, int, float]) -> bool:
|
||||
return time.time() >= self.next_time[key]
|
||||
|
||||
def start_cd(self, key, cd_time=0):
|
||||
self.next_time[key] = time.time() + (cd_time if cd_time > 0 else self.default_cd)
|
||||
def start_cd(self, key: Union[str, int, float], cd_time: int = 0):
|
||||
self.next_time[key] = time.time() + (
|
||||
cd_time if cd_time > 0 else self.default_cd
|
||||
)
|
||||
|
||||
def left_time(self, key) -> float:
|
||||
def left_time(self, key: Union[str, int, float]) -> float:
|
||||
return self.next_time[key] - time.time()
|
||||
|
||||
|
||||
static_flmt = FreqLimiter(15)
|
||||
|
||||
|
||||
# 恶意触发命令检测
|
||||
class BanCheckLimiter:
|
||||
"""
|
||||
恶意命令触发检测
|
||||
"""
|
||||
|
||||
def __init__(self, default_check_time: float = 5, default_count: int = 4):
|
||||
self.mint = defaultdict(int)
|
||||
self.mtime = defaultdict(float)
|
||||
self.default_check_time = default_check_time
|
||||
self.default_count = default_count
|
||||
|
||||
def add(self, key):
|
||||
def add(self, key: Union[str, int, float]):
|
||||
if self.mint[key] == 1:
|
||||
self.mtime[key] = time.time()
|
||||
self.mint[key] += 1
|
||||
|
||||
def check(self, key) -> bool:
|
||||
# print(self.mint[key])
|
||||
# print(time.time() - self.mtime[key])
|
||||
def check(self, key: Union[str, int, float]) -> bool:
|
||||
if time.time() - self.mtime[key] > self.default_check_time:
|
||||
self.mtime[key] = time.time()
|
||||
self.mint[key] = 0
|
||||
return False
|
||||
if self.mint[key] >= self.default_count and time.time() - self.mtime[key] < self.default_check_time:
|
||||
if (
|
||||
self.mint[key] >= self.default_count
|
||||
and time.time() - self.mtime[key] < self.default_check_time
|
||||
):
|
||||
self.mtime[key] = time.time()
|
||||
self.mint[key] = 0
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# 每日次数
|
||||
class DailyNumberLimiter:
|
||||
tz = pytz.timezone('Asia/Shanghai')
|
||||
"""
|
||||
每日调用命令次数限制
|
||||
"""
|
||||
|
||||
tz = pytz.timezone("Asia/Shanghai")
|
||||
|
||||
def __init__(self, max_num):
|
||||
self.today = -1
|
||||
@@ -123,7 +147,13 @@ class DailyNumberLimiter:
|
||||
self.count[key] = 0
|
||||
|
||||
|
||||
def is_number(s) -> bool:
|
||||
def is_number(s: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
检测 s 是否为数字
|
||||
参数:
|
||||
:param s: 文本
|
||||
"""
|
||||
try:
|
||||
float(s)
|
||||
return True
|
||||
@@ -131,6 +161,7 @@ def is_number(s) -> bool:
|
||||
pass
|
||||
try:
|
||||
import unicodedata
|
||||
|
||||
unicodedata.numeric(s)
|
||||
return True
|
||||
except (TypeError, ValueError):
|
||||
@@ -138,115 +169,156 @@ def is_number(s) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
# 获取bot
|
||||
def get_bot():
|
||||
def get_bot() -> Bot:
|
||||
"""
|
||||
说明:
|
||||
获取 bot 对象
|
||||
"""
|
||||
return list(nonebot.get_bots().values())[0]
|
||||
|
||||
|
||||
def get_message_at(data: str) -> list:
|
||||
def get_message_at(data: str) -> List[int]:
|
||||
"""
|
||||
说明:
|
||||
获取消息中所有的 at 对象的 qq
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
qq_list = []
|
||||
data = json.loads(data)
|
||||
try:
|
||||
for msg in data['message']:
|
||||
if msg['type'] == 'at':
|
||||
qq_list.append(int(msg['data']['qq']))
|
||||
return qq_list
|
||||
except Exception:
|
||||
return []
|
||||
for msg in data["message"]:
|
||||
if msg["type"] == "at":
|
||||
qq_list.append(int(msg["data"]["qq"]))
|
||||
return qq_list
|
||||
|
||||
|
||||
def get_message_imgs(data: str) -> list:
|
||||
def get_message_imgs(data: str) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
获取消息中所有的 图片 的链接
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
img_list = []
|
||||
data = json.loads(data)
|
||||
try:
|
||||
for msg in data['message']:
|
||||
if msg['type'] == 'image':
|
||||
img_list.append(msg['data']['url'])
|
||||
return img_list
|
||||
except Exception:
|
||||
return []
|
||||
for msg in data["message"]:
|
||||
if msg["type"] == "image":
|
||||
img_list.append(msg["data"]["url"])
|
||||
return img_list
|
||||
|
||||
|
||||
def get_message_text(data: str) -> str:
|
||||
"""
|
||||
说明:
|
||||
获取消息中 纯文本 的信息
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
data = json.loads(data)
|
||||
result = ''
|
||||
try:
|
||||
for msg in data['message']:
|
||||
if msg['type'] == 'text':
|
||||
result += msg['data']['text'].strip() + ' '
|
||||
return result.strip()
|
||||
except Exception:
|
||||
return ''
|
||||
result = ""
|
||||
for msg in data["message"]:
|
||||
if msg["type"] == "text":
|
||||
result += msg["data"]["text"].strip() + " "
|
||||
return result.strip()
|
||||
|
||||
|
||||
def get_message_type(data: str) -> str:
|
||||
return json.loads(data)['message_type']
|
||||
|
||||
|
||||
def get_message_record(data: str) -> str:
|
||||
def get_message_record(data: str) -> List[str]:
|
||||
"""
|
||||
说明:
|
||||
获取消息中所有 语音 的链接
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
record_list = []
|
||||
data = json.loads(data)
|
||||
try:
|
||||
for msg in data['message']:
|
||||
if msg['type'] == 'record':
|
||||
return msg['data']['url']
|
||||
return ''
|
||||
except Exception:
|
||||
return ''
|
||||
for msg in data["message"]:
|
||||
if msg["type"] == "record":
|
||||
record_list.append(msg["data"]["url"])
|
||||
return record_list
|
||||
|
||||
|
||||
def get_message_json(data: str) -> dict:
|
||||
def get_message_json(data: str) -> List[dict]:
|
||||
"""
|
||||
说明:
|
||||
获取消息中所有 json
|
||||
参数:
|
||||
:param data: event.json()
|
||||
"""
|
||||
json_list = []
|
||||
data = json.loads(data)
|
||||
try:
|
||||
for msg in data['message']:
|
||||
if msg['type'] == 'json':
|
||||
return msg['data']
|
||||
return {}
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def add_to_16(value):
|
||||
while len(value) % 16 != 0:
|
||||
value += '\0'
|
||||
return str.encode(value)
|
||||
for msg in data["message"]:
|
||||
if msg["type"] == "json":
|
||||
json_list.append(msg["data"])
|
||||
return json_list
|
||||
|
||||
|
||||
# 获取文本加密后的cookie
|
||||
def get_cookie_text(cookie_name: str) -> str:
|
||||
with open(TXT_PATH + "cookie/" + cookie_name + ".txt", 'r') as f:
|
||||
"""
|
||||
说明:
|
||||
获取 txt/cookie 目录下指定 cookie 的内容
|
||||
参数:
|
||||
:param cookie_name: cookie文件名称
|
||||
"""
|
||||
with open(TXT_PATH + "cookie/" + cookie_name + ".txt", "r") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
# 获取本地http代理
|
||||
def get_local_proxy():
|
||||
return system_proxy if system_proxy else None
|
||||
"""
|
||||
说明:
|
||||
获取 config.py 中设置的代理
|
||||
"""
|
||||
return SYSTEM_PROXY if SYSTEM_PROXY else None
|
||||
|
||||
|
||||
# 判断是否为中文
|
||||
def is_Chinese(word):
|
||||
def is_Chinese(word: str) -> bool:
|
||||
"""
|
||||
说明:
|
||||
判断字符串是否为纯中文
|
||||
参数:
|
||||
:param word: 文本
|
||||
"""
|
||||
for ch in word:
|
||||
if '\u4e00' <= ch <= '\u9fff':
|
||||
return True
|
||||
return False
|
||||
if not "\u4e00" <= ch <= "\u9fff":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
async def user_avatar(qq):
|
||||
url = f'http://q1.qlogo.cn/g?b=qq&nk={qq}&s=160'
|
||||
async def user_avatar(qq: int) -> bytes:
|
||||
"""
|
||||
说明:
|
||||
快捷获取用户头像
|
||||
参数:
|
||||
:param qq: qq号
|
||||
"""
|
||||
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=160"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, proxy=get_local_proxy(), timeout=5) as response:
|
||||
return await response.read()
|
||||
|
||||
|
||||
async def group_avatar(group_id):
|
||||
url = f'http://p.qlogo.cn/gh/{group_id}/{group_id}/640/'
|
||||
async def group_avatar(group_id: int) -> bytes:
|
||||
"""
|
||||
说明:
|
||||
快捷获取用群头像
|
||||
参数:
|
||||
:param group_id: 群号
|
||||
"""
|
||||
url = f"http://p.qlogo.cn/gh/{group_id}/{group_id}/640/"
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, proxy=get_local_proxy(), timeout=5) as response:
|
||||
return await response.read()
|
||||
|
||||
|
||||
def cn2py(word) -> str:
|
||||
def cn2py(word: str) -> str:
|
||||
"""
|
||||
说明:
|
||||
将字符串转化为拼音
|
||||
参数:
|
||||
:param word: 文本
|
||||
"""
|
||||
temp = ""
|
||||
for i in pypinyin.pinyin(word, style=pypinyin.NORMAL):
|
||||
temp += ''.join(i)
|
||||
temp += "".join(i)
|
||||
return temp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user