Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 915f186955 | |||
| a279e9b510 | |||
| f0a7cd4707 | |||
| c8b599f380 | |||
| 21e996a3b9 | |||
| a68c8bee98 | |||
| 6362ed4a88 | |||
| 7e3611afcd | |||
| c307aef5bb | |||
| bc8c6c49d6 | |||
| cf35e5923c | |||
| 4107a4875c | |||
| c8dae680a3 | |||
| adebd51605 | |||
| f0fdc930d4 |
@ -1,4 +1,5 @@
|
||||
/.env
|
||||
/.git
|
||||
/data
|
||||
|
||||
__pycache__
|
||||
3
.env.dev
@ -1,3 +1,2 @@
|
||||
DRIVER=~fastapi+~httpx+~websockets
|
||||
COMMAND_START=["!", "!", "", "/"]
|
||||
ALCONNA_USE_ORIGIN=true
|
||||
COMMAND_START=["!", "!", "", "/"]
|
||||
@ -1,3 +1,2 @@
|
||||
DRIVER=~fastapi+~httpx+~websockets
|
||||
COMMAND_START=["!", "!", "", "/"]
|
||||
ALCONNA_USE_ORIGIN=true
|
||||
COMMAND_START=["!", "!", "", "/"]
|
||||
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/.env
|
||||
/data
|
||||
|
||||
__pycache__
|
||||
38
konabot/plugins/memepack/__init__.py
Normal file
@ -0,0 +1,38 @@
|
||||
from io import BytesIO
|
||||
|
||||
from nonebot_plugin_alconna import (Alconna, Args, Field, MultiVar, UniMessage,
|
||||
on_alconna)
|
||||
|
||||
from konabot.plugins.memepack.drawing.geimao import draw_geimao
|
||||
from konabot.plugins.memepack.drawing.pt import draw_pt
|
||||
|
||||
geimao = on_alconna(Alconna(
|
||||
"给猫说",
|
||||
Args["saying", MultiVar(str, '+'), Field(
|
||||
missing_tips=lambda: "你没有写给猫说了什么"
|
||||
)]
|
||||
), use_cmd_start=True, use_cmd_sep=False, skip_for_unmatch=False, aliases={"给猫哈"})
|
||||
|
||||
@geimao.handle()
|
||||
async def _(saying: list[str]):
|
||||
img = await draw_geimao("\n".join(saying))
|
||||
img_bytes = BytesIO()
|
||||
img.save(img_bytes, format="PNG")
|
||||
|
||||
await geimao.send(await UniMessage().image(raw=img_bytes).export())
|
||||
|
||||
|
||||
pt = on_alconna(Alconna(
|
||||
"pt说",
|
||||
Args["saying", MultiVar(str, '+'), Field(
|
||||
missing_tips=lambda: "你没有写小帕说了什么"
|
||||
)]
|
||||
), use_cmd_start=True, use_cmd_sep=False, skip_for_unmatch=False, aliases={"小帕说"})
|
||||
|
||||
@pt.handle()
|
||||
async def _(saying: list[str]):
|
||||
img = await draw_pt("\n".join(saying))
|
||||
img_bytes = BytesIO()
|
||||
img.save(img_bytes, format="PNG")
|
||||
|
||||
await pt.send(await UniMessage().image(raw=img_bytes).export())
|
||||
BIN
konabot/plugins/memepack/assets/HarmonyOS_Sans_SC_Black.ttf
Normal file
BIN
konabot/plugins/memepack/assets/HarmonyOS_Sans_SC_Regular.ttf
Normal file
BIN
konabot/plugins/memepack/assets/NotoColorEmoji-Regular.ttf
Normal file
BIN
konabot/plugins/memepack/assets/geimao.jpg
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
konabot/plugins/memepack/assets/ptsay.png
Normal file
|
After Width: | Height: | Size: 272 KiB |
0
konabot/plugins/memepack/drawing/__init__.py
Normal file
0
konabot/plugins/memepack/drawing/base/__init__.py
Normal file
12
konabot/plugins/memepack/drawing/base/fonts.py
Normal file
@ -0,0 +1,12 @@
|
||||
from imagetext_py import EmojiOptions, FontDB
|
||||
|
||||
from .path import ASSETS
|
||||
|
||||
FontDB.LoadFromDir(str(ASSETS))
|
||||
|
||||
FontDB.SetDefaultEmojiOptions(EmojiOptions(
|
||||
parse_shortcodes=False,
|
||||
))
|
||||
|
||||
HARMONYOS_SANS_SC_BLACK = FontDB.Query("HarmonyOS_Sans_SC_Black")
|
||||
HARMONYOS_SANS_SC_REGULAR = FontDB.Query("HarmonyOS_Sans_SC_Regular")
|
||||
3
konabot/plugins/memepack/drawing/base/path.py
Normal file
@ -0,0 +1,3 @@
|
||||
from pathlib import Path
|
||||
|
||||
ASSETS = Path(__file__).parent.parent.parent / "assets"
|
||||
29
konabot/plugins/memepack/drawing/geimao.py
Normal file
@ -0,0 +1,29 @@
|
||||
import asyncio
|
||||
from typing import Any, cast
|
||||
|
||||
import imagetext_py
|
||||
import PIL.Image
|
||||
|
||||
from .base.fonts import HARMONYOS_SANS_SC_BLACK
|
||||
from .base.path import ASSETS
|
||||
|
||||
geimao_image = PIL.Image.open(ASSETS / "geimao.jpg").convert("RGBA")
|
||||
|
||||
|
||||
def _draw_geimao(saying: str):
|
||||
img = geimao_image.copy()
|
||||
with imagetext_py.Writer(img) as iw:
|
||||
iw.draw_text_wrapped(
|
||||
saying, 960, 50, 00.5, 0, 1920, 240, HARMONYOS_SANS_SC_BLACK,
|
||||
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
|
||||
0.8,
|
||||
imagetext_py.TextAlign.Center,
|
||||
cast(Any, 30.0),
|
||||
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("FFFFFFFF")),
|
||||
draw_emojis=True,
|
||||
)
|
||||
return img
|
||||
|
||||
|
||||
async def draw_geimao(saying: str):
|
||||
return await asyncio.to_thread(_draw_geimao, saying)
|
||||
26
konabot/plugins/memepack/drawing/pt.py
Normal file
@ -0,0 +1,26 @@
|
||||
import asyncio
|
||||
|
||||
import imagetext_py
|
||||
import PIL.Image
|
||||
|
||||
from .base.fonts import HARMONYOS_SANS_SC_REGULAR
|
||||
from .base.path import ASSETS
|
||||
|
||||
pt_image = PIL.Image.open(ASSETS / "ptsay.png").convert("RGBA")
|
||||
|
||||
|
||||
def _draw_pt(saying: str):
|
||||
img = pt_image.copy()
|
||||
with imagetext_py.Writer(img) as iw:
|
||||
iw.draw_text_wrapped(
|
||||
saying, 259, 278, 0.5, 0.5, 360, 48, HARMONYOS_SANS_SC_REGULAR,
|
||||
imagetext_py.Paint.Color(imagetext_py.Color.from_hex("000000FF")),
|
||||
1.0,
|
||||
imagetext_py.TextAlign.Center,
|
||||
draw_emojis=True,
|
||||
)
|
||||
return img
|
||||
|
||||
|
||||
async def draw_pt(saying: str):
|
||||
return await asyncio.to_thread(_draw_pt, saying)
|
||||
46
konabot/plugins/openssl_rand/__init__.py
Normal file
@ -0,0 +1,46 @@
|
||||
import base64
|
||||
import secrets
|
||||
from typing import Literal
|
||||
|
||||
from nonebot.adapters import Event as BaseEvent
|
||||
from nonebot.adapters.discord.event import MessageEvent as DiscordMessageEvent
|
||||
from nonebot_plugin_alconna import (Alconna, Args, Field, Subcommand,
|
||||
UniMessage, on_alconna)
|
||||
|
||||
evt = on_alconna(Alconna(
|
||||
"openssl",
|
||||
Subcommand(
|
||||
"rand",
|
||||
Args["mode", Literal["-hex", "-base64"], Field(
|
||||
missing_tips=lambda: "请输入生成模式,-hex 或 -base64,例如 openssl rand -hex 16",
|
||||
unmatch_tips=lambda mode: f"{mode} 不是一个有效的格式,请使用 -hex 或 -base64"
|
||||
)],
|
||||
Args["num", int, Field(
|
||||
missing_tips=lambda: "请输入需要生成的字节数,例如 openssl rand -hex 16",
|
||||
)],
|
||||
)
|
||||
), use_cmd_start=True, use_cmd_sep=False, skip_for_unmatch=False)
|
||||
|
||||
@evt.assign("rand")
|
||||
async def _(event: BaseEvent, mode: str, num: int):
|
||||
if num <= 0:
|
||||
await evt.send(await UniMessage().text(
|
||||
"生成的字节数必须是一个正整数"
|
||||
).export())
|
||||
return
|
||||
if num > 256:
|
||||
await evt.send(await UniMessage().text(
|
||||
"太大了!!!!!"
|
||||
).export())
|
||||
return
|
||||
|
||||
random_bytes = secrets.token_bytes(num)
|
||||
if mode == "-hex":
|
||||
result = random_bytes.hex()
|
||||
else:
|
||||
result = base64.b64encode(random_bytes).decode()
|
||||
|
||||
if isinstance(event, DiscordMessageEvent):
|
||||
result = f"```{result}```"
|
||||
|
||||
await evt.send(await UniMessage().text(result).export())
|
||||
@ -1,12 +1,42 @@
|
||||
from nonebot_plugin_alconna import Alconna, Args, Field, UniMessage, on_alconna
|
||||
from typing import Optional
|
||||
from nonebot.adapters import Event as BaseEvent
|
||||
from nonebot.adapters.console.event import MessageEvent as ConsoleMessageEvent
|
||||
from nonebot.adapters.discord.event import MessageEvent as DiscordMessageEvent
|
||||
from nonebot_plugin_alconna import Alconna, Args, UniMessage, on_alconna
|
||||
|
||||
from konabot.plugins.roll_dice.roll_dice import roll_dice
|
||||
from konabot.plugins.weather.fetcher import fetch_radar
|
||||
from konabot.plugins.roll_dice.roll_dice import generate_dice_image
|
||||
from konabot.plugins.roll_dice.roll_number import get_random_number, roll_number
|
||||
|
||||
evt = on_alconna(Alconna(
|
||||
"摇骰子"
|
||||
"摇数字"
|
||||
), use_cmd_start=True, use_cmd_sep=False, skip_for_unmatch=True)
|
||||
|
||||
@evt.handle()
|
||||
async def _():
|
||||
await evt.send(await UniMessage().text(await roll_dice()).export())
|
||||
async def _(event: BaseEvent):
|
||||
if isinstance(event, DiscordMessageEvent):
|
||||
await evt.send(await UniMessage().text("```\n" + roll_number() + "\n```").export())
|
||||
elif isinstance(event, ConsoleMessageEvent):
|
||||
await evt.send(await UniMessage().text(roll_number()).export())
|
||||
else:
|
||||
await evt.send(await UniMessage().text(roll_number(wide=True)).export())
|
||||
|
||||
evt = on_alconna(Alconna(
|
||||
"摇骰子",
|
||||
Args["f1?", int]["f2?", int]
|
||||
), use_cmd_start=True, use_cmd_sep=False, skip_for_unmatch=True)
|
||||
|
||||
@evt.handle()
|
||||
async def _(event: BaseEvent, f1: Optional[int] = None, f2: Optional[int] = None):
|
||||
# if isinstance(event, DiscordMessageEvent):
|
||||
# await evt.send(await UniMessage().text("```\n" + roll_dice() + "\n```").export())
|
||||
# elif isinstance(event, ConsoleMessageEvent):
|
||||
number = 0
|
||||
if(f1 is not None and f2 is not None):
|
||||
number = get_random_number(f1, f2)
|
||||
elif f1 is not None:
|
||||
number = get_random_number(1, f1)
|
||||
else:
|
||||
number = get_random_number()
|
||||
await evt.send(await UniMessage().image(raw=await generate_dice_image(number)).export())
|
||||
# else:
|
||||
# await evt.send(await UniMessage().text(roll_dice(wide=True)).export())
|
||||
|
||||
BIN
konabot/plugins/roll_dice/assets/1.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
konabot/plugins/roll_dice/assets/10.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
konabot/plugins/roll_dice/assets/11.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
konabot/plugins/roll_dice/assets/12.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
konabot/plugins/roll_dice/assets/2.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
konabot/plugins/roll_dice/assets/3.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
konabot/plugins/roll_dice/assets/4.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
konabot/plugins/roll_dice/assets/5.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
konabot/plugins/roll_dice/assets/6.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
konabot/plugins/roll_dice/assets/7.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
konabot/plugins/roll_dice/assets/8.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
konabot/plugins/roll_dice/assets/9.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
konabot/plugins/roll_dice/assets/montserrat.otf
Normal file
BIN
konabot/plugins/roll_dice/assets/template.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
3
konabot/plugins/roll_dice/base/path.py
Normal file
@ -0,0 +1,3 @@
|
||||
from pathlib import Path
|
||||
|
||||
ASSETS = Path(__file__).parent.parent / "assets"
|
||||
@ -1,46 +1,203 @@
|
||||
number_arts = {
|
||||
1: ''' _
|
||||
/ |
|
||||
| |
|
||||
| |
|
||||
|_|
|
||||
from io import BytesIO
|
||||
import cv2
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
from konabot.plugins.roll_dice.base.path import ASSETS
|
||||
|
||||
def text_to_transparent_image(text, font_size=40, padding=0, text_color=(0, 0, 0)):
|
||||
"""
|
||||
将文本转换为带透明背景的图像,图像大小刚好包含文本
|
||||
"""
|
||||
# 创建临时图像来计算文本尺寸
|
||||
temp_image = Image.new('RGB', (1, 1), (255, 255, 255))
|
||||
temp_draw = ImageDraw.Draw(temp_image)
|
||||
|
||||
''',
|
||||
2: ''' ____
|
||||
|___ \
|
||||
__) |
|
||||
/ __/
|
||||
|_____|
|
||||
''',
|
||||
3: ''' _____
|
||||
|___ /
|
||||
|_ \
|
||||
___) |
|
||||
|____/
|
||||
''',
|
||||
4: ''' _ _
|
||||
| || |
|
||||
| || |_
|
||||
|__ _|
|
||||
|_|
|
||||
''',
|
||||
5: ''' ____
|
||||
| ___|
|
||||
|___ \
|
||||
___) |
|
||||
|____/
|
||||
''',
|
||||
6: ''' __
|
||||
/ /_
|
||||
| '_ \
|
||||
| (_) |
|
||||
\___/
|
||||
'''
|
||||
}
|
||||
font = ImageFont.truetype(ASSETS / "montserrat.otf", font_size)
|
||||
# try:
|
||||
# font = ImageFont.truetype(ASSETS / "montserrat.otf", font_size)
|
||||
# except:
|
||||
# try:
|
||||
# font = ImageFont.truetype("arial.ttf", font_size)
|
||||
# except:
|
||||
# # 如果系统字体不可用,使用默认字体
|
||||
# font = ImageFont.load_default()
|
||||
|
||||
# 获取文本边界框
|
||||
bbox = temp_draw.textbbox((0, 0), text, font=font)
|
||||
text_width = bbox[2] - bbox[0]
|
||||
text_height = bbox[3] - bbox[1]
|
||||
|
||||
# 计算图像大小(文本大小 + 内边距)
|
||||
image_width = int(text_width + 2 * padding)
|
||||
image_height = int(text_height + 2 * padding)
|
||||
|
||||
# 创建RGBA模式的空白图像(带透明通道)
|
||||
image = Image.new('RGBA', (image_width, image_height), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
# 绘制文本(考虑内边距)
|
||||
x = padding - bbox[0] # 调整起始位置
|
||||
y = padding - bbox[1]
|
||||
|
||||
# 设置文本颜色(带透明度)
|
||||
if len(text_color) == 3:
|
||||
text_color = text_color + (255,) # 添加完全不透明的alpha值
|
||||
|
||||
draw.text((x, y), text, fill=text_color, font=font)
|
||||
|
||||
# 转换为OpenCV格式(BGRA)
|
||||
image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGBA2BGRA)
|
||||
return image_cv
|
||||
|
||||
def get_random_number(min: int = 1, max: int = 6) -> int:
|
||||
import random
|
||||
return random.randint(min, max)
|
||||
def perspective_transform(image, target, corners):
|
||||
"""
|
||||
对图像进行透视变换(保持透明通道)
|
||||
target: 画布
|
||||
corners: 四个角点的坐标,顺序为 [左上, 右上, 右下, 左下]
|
||||
"""
|
||||
height, width = image.shape[:2]
|
||||
|
||||
# 源点(原始图像的四个角)
|
||||
src_points = np.array([
|
||||
[0, 0], # 左上
|
||||
[width-1, 0], # 右上
|
||||
[width-1, height-1], # 右下
|
||||
[0, height-1] # 左下
|
||||
], dtype=np.float32)
|
||||
|
||||
# 目标点(变换后的四个角)
|
||||
dst_points = np.array(corners, dtype=np.float32)
|
||||
|
||||
# 计算透视变换矩阵
|
||||
matrix = cv2.getPerspectiveTransform(src_points, dst_points)
|
||||
|
||||
# 获取画布大小
|
||||
target_height, target_width = target.shape[:2]
|
||||
|
||||
async def roll_dice() -> str:
|
||||
return number_arts[get_random_number()]
|
||||
# 应用透视变换(保持所有通道,包括alpha)
|
||||
transformed = cv2.warpPerspective(image, matrix, (target_width, target_height), flags=cv2.INTER_LINEAR)
|
||||
|
||||
return transformed, matrix
|
||||
|
||||
def blend_with_transparency(background, foreground, position):
|
||||
"""
|
||||
将带透明通道的前景图像合成到背景图像上
|
||||
position: 前景图像在背景图像上的位置 (x, y)
|
||||
"""
|
||||
bg = background.copy()
|
||||
|
||||
# 如果背景没有alpha通道,添加一个
|
||||
if bg.shape[2] == 3:
|
||||
bg = cv2.cvtColor(bg, cv2.COLOR_BGR2BGRA)
|
||||
bg[:, :, 3] = 255 # 完全不透明
|
||||
|
||||
x, y = position
|
||||
fg_height, fg_width = foreground.shape[:2]
|
||||
bg_height, bg_width = bg.shape[:2]
|
||||
|
||||
# 确保位置在图像范围内
|
||||
x = max(0, min(x, bg_width - fg_width))
|
||||
y = max(0, min(y, bg_height - fg_height))
|
||||
|
||||
# 提取前景的alpha通道并归一化
|
||||
alpha_foreground = foreground[:, :, 3] / 255.0
|
||||
|
||||
# 对于每个颜色通道进行合成
|
||||
for c in range(3):
|
||||
bg_region = bg[y:y+fg_height, x:x+fg_width, c]
|
||||
fg_region = foreground[:, :, c]
|
||||
|
||||
# alpha混合公式
|
||||
bg[y:y+fg_height, x:x+fg_width, c] = (
|
||||
alpha_foreground * fg_region +
|
||||
(1 - alpha_foreground) * bg_region
|
||||
)
|
||||
|
||||
# 更新背景的alpha通道(如果需要)
|
||||
bg_alpha_region = bg[y:y+fg_height, x:x+fg_width, 3]
|
||||
bg[y:y+fg_height, x:x+fg_width, 3] = np.maximum(bg_alpha_region, foreground[:, :, 3])
|
||||
|
||||
return bg
|
||||
|
||||
def precise_blend_with_perspective(background, foreground, corners):
|
||||
"""
|
||||
精确合成:根据四个角点将前景图像透视合成到背景上
|
||||
"""
|
||||
# 创建与背景相同大小的空白图像
|
||||
bg_height, bg_width = background.shape[:2]
|
||||
|
||||
# 如果背景没有alpha通道,转换为BGRA
|
||||
if background.shape[2] == 3:
|
||||
background_bgra = cv2.cvtColor(background, cv2.COLOR_BGR2BGRA)
|
||||
else:
|
||||
background_bgra = background.copy()
|
||||
|
||||
# 创建与背景相同大小的前景图层
|
||||
foreground_layer = np.zeros((bg_height, bg_width, 4), dtype=np.uint8)
|
||||
|
||||
# 计算前景图像在背景中的边界框
|
||||
min_x = int(min(corners[:, 0]))
|
||||
max_x = int(max(corners[:, 0]))
|
||||
min_y = int(min(corners[:, 1]))
|
||||
max_y = int(max(corners[:, 1]))
|
||||
|
||||
# 将变换后的前景图像放置到对应位置
|
||||
fg_height, fg_width = foreground.shape[:2]
|
||||
if min_y + fg_height <= bg_height and min_x + fg_width <= bg_width:
|
||||
foreground_layer[min_y:min_y+fg_height, min_x:min_x+fg_width] = foreground
|
||||
|
||||
# 创建掩码(只在前景有内容的地方合成)
|
||||
mask = (foreground_layer[:, :, 3] > 0)
|
||||
|
||||
# 合成图像
|
||||
result = background_bgra.copy()
|
||||
for c in range(3):
|
||||
result[:, :, c][mask] = foreground_layer[:, :, c][mask]
|
||||
result[:, :, 3][mask] = foreground_layer[:, :, 3][mask]
|
||||
|
||||
return result
|
||||
|
||||
async def generate_dice_image(number: int) -> BytesIO:
|
||||
# 将文本转换为带透明背景的图像
|
||||
text = str(number)
|
||||
text_image = text_to_transparent_image(
|
||||
text,
|
||||
font_size=60,
|
||||
text_color=(0, 0, 0) # 黑色文字
|
||||
)
|
||||
|
||||
# 定义3D变换的四个角点(透视效果)
|
||||
# 顺序: [左上, 右上, 右下, 左下]
|
||||
corners = np.array([
|
||||
[16, 30], # 左上
|
||||
[51, 5], # 右上(上移,创建透视)
|
||||
[88, 33], # 右下
|
||||
[49, 62] # 左下(下移)
|
||||
], dtype=np.float32)
|
||||
|
||||
# 加载背景图像,保留透明通道
|
||||
background = cv2.imread(str(ASSETS / "template.png"), cv2.IMREAD_UNCHANGED)
|
||||
|
||||
|
||||
# 对文本图像进行3D变换(保持透明通道)
|
||||
transformed_text, transform_matrix = perspective_transform(text_image, background, corners)
|
||||
|
||||
min_x = int(min(corners[:, 0]))
|
||||
min_y = int(min(corners[:, 1]))
|
||||
final_image_simple = blend_with_transparency(background, transformed_text, (min_x, min_y))
|
||||
|
||||
pil_final = Image.fromarray(final_image_simple)
|
||||
# 导入一系列图像
|
||||
images: list[Image.Image] = [Image.open(ASSETS / f"{i}.png") for i in range(1, 12)]
|
||||
images.append(pil_final)
|
||||
frame_durations = [100] * (len(images) - 1) + [100000]
|
||||
# 保存为BytesIO对象
|
||||
output = BytesIO()
|
||||
images[0].save(output,
|
||||
save_all=True,
|
||||
append_images=images[1:],
|
||||
duration=frame_durations,
|
||||
format='GIF',
|
||||
loop=1)
|
||||
return output
|
||||
54
konabot/plugins/roll_dice/roll_number.py
Normal file
@ -0,0 +1,54 @@
|
||||
number_arts = {
|
||||
1: ''' _
|
||||
/ |
|
||||
| |
|
||||
| |
|
||||
|_|
|
||||
|
||||
''',
|
||||
2: ''' ____
|
||||
|___ \\
|
||||
__) |
|
||||
/ __/
|
||||
|_____|
|
||||
''',
|
||||
3: ''' _____
|
||||
|___ /
|
||||
|_ \\
|
||||
___) |
|
||||
|____/
|
||||
''',
|
||||
4: ''' _ _
|
||||
| || |
|
||||
| || |_
|
||||
|__ _|
|
||||
|_|
|
||||
''',
|
||||
5: ''' ____
|
||||
| ___|
|
||||
|___ \\
|
||||
___) |
|
||||
|____/
|
||||
''',
|
||||
6: ''' __
|
||||
/ /_
|
||||
| '_ \\
|
||||
| (_) |
|
||||
\\___/
|
||||
'''
|
||||
}
|
||||
|
||||
def get_random_number(min: int = 1, max: int = 6) -> int:
|
||||
import random
|
||||
return random.randint(min, max)
|
||||
|
||||
def roll_number(wide: bool = False) -> str:
|
||||
raw = number_arts[get_random_number()]
|
||||
if wide:
|
||||
raw = (raw
|
||||
.replace("/", "/")
|
||||
.replace("\\", "\")
|
||||
.replace("_", "_")
|
||||
.replace("|", "|")
|
||||
.replace(" ", " "))
|
||||
return raw
|
||||
340
konabot/plugins/simple_notify/__init__.py
Normal file
@ -0,0 +1,340 @@
|
||||
import asyncio
|
||||
import datetime
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal, cast
|
||||
|
||||
import nonebot
|
||||
from loguru import logger
|
||||
from nonebot import on_message
|
||||
from nonebot.adapters import Event
|
||||
from nonebot.adapters.console import Bot as ConsoleBot
|
||||
from nonebot.adapters.console.event import MessageEvent as ConsoleMessageEvent
|
||||
from nonebot.adapters.discord import Bot as DiscordBot
|
||||
from nonebot.adapters.discord.event import MessageEvent as DiscordMessageEvent
|
||||
from nonebot.adapters.onebot.v11 import Bot as OnebotV11Bot
|
||||
from nonebot.adapters.onebot.v11.event import \
|
||||
GroupMessageEvent as OnebotV11GroupMessageEvent
|
||||
from nonebot.adapters.onebot.v11.event import \
|
||||
MessageEvent as OnebotV11MessageEvent
|
||||
from nonebot_plugin_alconna import UniMessage, UniMsg
|
||||
from pydantic import BaseModel
|
||||
|
||||
PATTERN_DELTA_HMS = re.compile(r"^((\d+|[零一两二三四五六七八九十]+) ?天)?((\d+|[零一两二三四五六七八九十]+) ?个?小?时)?((\d+|[零一两二三四五六七八九十]+) ?分钟?)?((\d+|[零一两二三四五六七八九十]+) ?秒钟?)? ?后 ?$")
|
||||
|
||||
PATTERN_DATE_SPECIFY = re.compile(r"(\d{1,2}|[零一二三四五六七八九十]+) ?[日号]")
|
||||
PATTERN_MONTH_SPECIFY = re.compile(r"(\d{1,2}|[零一二三四五六七八九十]+) ?月")
|
||||
PATTERN_YEAR_SPECIFY = re.compile(r"(\d|[零一二三四五六七八九十]+) ?年")
|
||||
PATTERN_HOUR_SPECIFY = re.compile(r"(\d|[零一二三四五六七八九十]+) ?[点时]钟?")
|
||||
PATTERN_MINUTE_SPECIFY = re.compile(r"(\d|[零一二三四五六七八九十]+) ?分(钟)?")
|
||||
PATTERN_SECOND_SPECIFY = re.compile(r"(\d|[零一二三四五六七八九十]+) ?秒(钟)?")
|
||||
PATTERN_HMS_SPECIFY = re.compile(r"\d\d[::]\d\d([::]\d\d)?")
|
||||
PATTERN_PM_SPECIFY = re.compile(r"(下午|PM|晚上)")
|
||||
|
||||
|
||||
def parse_chinese_or_digit(s: str) -> int:
|
||||
if set(s) <= set("0123456789"):
|
||||
return int(s)
|
||||
|
||||
s = s.replace("两", "二")
|
||||
|
||||
chinese_digits = {
|
||||
'一': 1, '二': 2, '三': 3, '四': 4, '五': 5,
|
||||
'六': 6, '七': 7, '八': 8, '九': 9, '十': 10
|
||||
}
|
||||
|
||||
if s in chinese_digits:
|
||||
return chinese_digits[s]
|
||||
|
||||
if len(s) == 2 and s[0] == '十':
|
||||
if s[1] in chinese_digits:
|
||||
return 10 + chinese_digits[s[1]] - 1 # e.g., "十一" = 10 + 1 = 11
|
||||
|
||||
try:
|
||||
chinese_to_arabic = {
|
||||
'零': 0, '一': 1, '二': 2, '三': 3, '四': 4,
|
||||
'五': 5, '六': 6, '七': 7, '八': 8, '九': 9,
|
||||
'十': 10
|
||||
}
|
||||
|
||||
if s in chinese_to_arabic:
|
||||
return chinese_to_arabic[s]
|
||||
|
||||
if len(s) == 2 and s[0] == '十' and s[1] in chinese_to_arabic:
|
||||
return 10 + chinese_to_arabic[s[1]]
|
||||
except (ValueError, KeyError):
|
||||
pass
|
||||
|
||||
try:
|
||||
return int(s)
|
||||
except ValueError:
|
||||
return -1
|
||||
|
||||
|
||||
def get_target_time(content: str) -> datetime.datetime | None:
|
||||
if match := re.match(PATTERN_DELTA_HMS, content.strip()):
|
||||
days = parse_chinese_or_digit(match.group(2) or "0")
|
||||
hours = parse_chinese_or_digit(match.group(4) or "0")
|
||||
minutes = parse_chinese_or_digit(match.group(6) or "0")
|
||||
seconds = parse_chinese_or_digit(match.group(8) or "0")
|
||||
return datetime.datetime.now() + datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
|
||||
|
||||
t = datetime.datetime.now()
|
||||
content_to_match = content
|
||||
if "明天" in content_to_match:
|
||||
content_to_match = "".join(content_to_match.split("明天"))
|
||||
t += datetime.timedelta(days=1)
|
||||
elif "后天" in content_to_match:
|
||||
content_to_match = "".join(content_to_match.split("后天"))
|
||||
t += datetime.timedelta(days=2)
|
||||
elif "今天" in content_to_match:
|
||||
content_to_match = "".join(content_to_match.split("今天"))
|
||||
|
||||
if match1 := re.match(PATTERN_DATE_SPECIFY, content_to_match):
|
||||
content_to_match = "".join(content_to_match.split(match1.group(0)))
|
||||
day = parse_chinese_or_digit(match1.group(1))
|
||||
if day <= 0 or day > 31:
|
||||
return
|
||||
if day < t.day:
|
||||
if t.month == 12:
|
||||
t = t.replace(year=t.year + 1, month=1, day=day)
|
||||
else:
|
||||
t = t.replace(month=t.month + 1, day=day)
|
||||
else:
|
||||
t = t.replace(day=day)
|
||||
if match2 := re.match(PATTERN_MONTH_SPECIFY, content_to_match):
|
||||
content_to_match = "".join(content_to_match.split(match2.group(0)))
|
||||
month = parse_chinese_or_digit(match2.group(1))
|
||||
if month <= 0 or month > 12:
|
||||
return
|
||||
if month < t.month:
|
||||
t = t.replace(year=t.year + 1, month=month)
|
||||
else:
|
||||
t = t.replace(month=month)
|
||||
if match3 := re.match(PATTERN_YEAR_SPECIFY, content_to_match):
|
||||
content_to_match = "".join(content_to_match.split(match3.group(0)))
|
||||
year = parse_chinese_or_digit(match3.group(1))
|
||||
if year < 100:
|
||||
year += 2000
|
||||
if year < t.year:
|
||||
return
|
||||
t = t.replace(year=year)
|
||||
if match4 := re.match(PATTERN_HOUR_SPECIFY, content_to_match):
|
||||
content_to_match = "".join(content_to_match.split(match4.group(0)))
|
||||
hour = parse_chinese_or_digit(match4.group(1))
|
||||
if hour < 0 or hour > 23:
|
||||
return
|
||||
t = t.replace(hour=hour)
|
||||
if match5 := re.match(PATTERN_MINUTE_SPECIFY, content_to_match):
|
||||
content_to_match = "".join(content_to_match.split(match5.group(0)))
|
||||
minute = parse_chinese_or_digit(match5.group(1))
|
||||
if minute < 0 or minute > 59:
|
||||
return
|
||||
t = t.replace(minute=minute)
|
||||
if match6 := re.match(PATTERN_SECOND_SPECIFY, content_to_match):
|
||||
content_to_match = "".join(content_to_match.split(match6.group(0)))
|
||||
second = parse_chinese_or_digit(match6.group(1))
|
||||
if second < 0 or second > 59:
|
||||
return
|
||||
t = t.replace(second=second)
|
||||
if match7 := re.match(PATTERN_HMS_SPECIFY, content_to_match):
|
||||
content_to_match = "".join(content_to_match.split(match7.group(0)))
|
||||
hms = match7.group(0).replace(":", ":").split(":")
|
||||
if len(hms) >= 2:
|
||||
hour = int(hms[0])
|
||||
minute = int(hms[1])
|
||||
if hour < 0 or hour > 23 or minute < 0 or minute > 59:
|
||||
return
|
||||
t = t.replace(hour=hour, minute=minute)
|
||||
if len(hms) == 3:
|
||||
second = int(hms[2])
|
||||
if second < 0 or second > 59:
|
||||
return
|
||||
t = t.replace(second=second)
|
||||
|
||||
content_to_match = content_to_match.replace("上午", "").replace("AM", "").replace("凌晨", "")
|
||||
if match8 := re.match(PATTERN_PM_SPECIFY, content_to_match):
|
||||
content_to_match = "".join(content_to_match.split(match8.group(0)))
|
||||
if t.hour < 12:
|
||||
t = t.replace(hour=t.hour + 12)
|
||||
if t.hour == 12:
|
||||
t += datetime.timedelta(hours=12)
|
||||
|
||||
if len(content_to_match.strip()) != 0:
|
||||
return
|
||||
if t < datetime.datetime.now():
|
||||
t += datetime.timedelta(days=1)
|
||||
return t
|
||||
|
||||
|
||||
evt = on_message()
|
||||
|
||||
(Path(__file__).parent.parent.parent.parent / "data").mkdir(exist_ok=True)
|
||||
DATA_FILE_PATH = Path(__file__).parent.parent.parent.parent / "data" / "notify.json"
|
||||
DATA_FILE_LOCK = asyncio.Lock()
|
||||
|
||||
|
||||
class Notify(BaseModel):
|
||||
platform: Literal["console", "qq", "discord"]
|
||||
|
||||
target: str
|
||||
"需要接受通知的个体"
|
||||
|
||||
target_env: str | None
|
||||
"在哪里进行通知,如果是 None 代表私聊通知"
|
||||
|
||||
notify_time: datetime.datetime
|
||||
notify_msg: str
|
||||
|
||||
def get_str(self):
|
||||
return f"{self.target}-{self.target_env}-{self.platform}-{self.notify_time}"
|
||||
|
||||
|
||||
class NotifyConfigFile(BaseModel):
|
||||
version: int = 1
|
||||
notifies: list[Notify] = []
|
||||
unsent: list[Notify] = []
|
||||
|
||||
|
||||
def load_notify_config() -> NotifyConfigFile:
|
||||
if not DATA_FILE_PATH.exists():
|
||||
return NotifyConfigFile()
|
||||
try:
|
||||
return NotifyConfigFile.model_validate_json(DATA_FILE_PATH.read_text())
|
||||
except Exception as e:
|
||||
logger.warning(f"在解析 Notify 时遇到问题:{e}")
|
||||
return NotifyConfigFile()
|
||||
|
||||
|
||||
def save_notify_config(config: NotifyConfigFile):
|
||||
DATA_FILE_PATH.write_text(config.model_dump_json(indent=4))
|
||||
|
||||
|
||||
async def notify_now(notify: Notify):
|
||||
if notify.platform == 'console':
|
||||
bot = [b for b in nonebot.get_bots().values() if isinstance(b, ConsoleBot)]
|
||||
if len(bot) != 1:
|
||||
logger.warning(f"提醒未成功发送出去:{nonebot.get_bots()} {notify}")
|
||||
return False
|
||||
bot = bot[0]
|
||||
await bot.send_private_message(notify.target, f"代办通知:{notify.notify_msg}")
|
||||
elif notify.platform == 'discord':
|
||||
bot = [b for b in nonebot.get_bots().values() if isinstance(b, DiscordBot)]
|
||||
if len(bot) != 1:
|
||||
logger.warning(f"提醒未成功发送出去:{nonebot.get_bots()} {notify}")
|
||||
return False
|
||||
bot = bot[0]
|
||||
channel = await bot.create_DM(recipient_id=int(notify.target))
|
||||
await bot.send_to(channel.id, f"代办通知:{notify.notify_msg}")
|
||||
elif notify.platform == 'qq':
|
||||
bot = [b for b in nonebot.get_bots().values() if isinstance(b, OnebotV11Bot)]
|
||||
if len(bot) != 1:
|
||||
logger.warning(f"提醒未成功发送出去:{nonebot.get_bots()} {notify}")
|
||||
return False
|
||||
bot = bot[0]
|
||||
if notify.target_env is None:
|
||||
await bot.send_private_msg(
|
||||
user_id=int(notify.target),
|
||||
message=f"代办通知:{notify.notify_msg}",
|
||||
)
|
||||
else:
|
||||
await bot.send_group_msg(
|
||||
group_id=int(notify.target_env),
|
||||
message=cast(Any,
|
||||
await UniMessage().at(notify.target).text(f"代办通知:{notify.notify_msg}").export()
|
||||
),
|
||||
)
|
||||
else:
|
||||
logger.warning(f"提醒未成功发送出去:{notify}")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
async def create_notify_task(notify: Notify, fail2remove: bool = True):
|
||||
async def mission():
|
||||
begin_time = datetime.datetime.now()
|
||||
if begin_time < notify.notify_time:
|
||||
await asyncio.sleep((notify.notify_time - begin_time).total_seconds())
|
||||
res = await notify_now(notify)
|
||||
if fail2remove or res:
|
||||
await DATA_FILE_LOCK.acquire()
|
||||
cfg = load_notify_config()
|
||||
cfg.notifies = [n for n in cfg.notifies if n.get_str() != notify.get_str()]
|
||||
if not res:
|
||||
cfg.unsent.append(notify)
|
||||
save_notify_config(cfg)
|
||||
DATA_FILE_LOCK.release()
|
||||
else:
|
||||
pass
|
||||
return asyncio.create_task(mission())
|
||||
|
||||
|
||||
@evt.handle()
|
||||
async def _(msg: UniMsg, mEvt: Event):
|
||||
text = msg.extract_plain_text()
|
||||
if "提醒我" not in text:
|
||||
return
|
||||
|
||||
segments = text.split("提醒我")
|
||||
if len(segments) != 2:
|
||||
return
|
||||
|
||||
notify_time, notify_text = segments
|
||||
target_time = get_target_time(notify_time)
|
||||
if target_time is None:
|
||||
logger.info(f"无法从 {notify_time} 中解析出时间")
|
||||
return
|
||||
if not notify_text:
|
||||
return
|
||||
|
||||
await DATA_FILE_LOCK.acquire()
|
||||
cfg = load_notify_config()
|
||||
|
||||
if isinstance(mEvt, ConsoleMessageEvent):
|
||||
platform = "console"
|
||||
target = mEvt.get_user_id()
|
||||
target_env = None
|
||||
elif isinstance(mEvt, OnebotV11MessageEvent):
|
||||
platform = "qq"
|
||||
target = mEvt.get_user_id()
|
||||
if isinstance(mEvt, OnebotV11GroupMessageEvent):
|
||||
target_env = str(mEvt.group_id)
|
||||
else:
|
||||
target_env = None
|
||||
elif isinstance(mEvt, DiscordMessageEvent):
|
||||
platform = "discord"
|
||||
target = mEvt.get_user_id()
|
||||
target_env = None
|
||||
else:
|
||||
logger.warning(f"Notify 遇到不支持的平台:{type(mEvt).__name__}")
|
||||
return
|
||||
|
||||
notify = Notify(
|
||||
platform=platform,
|
||||
target=target,
|
||||
target_env=target_env,
|
||||
notify_time=target_time,
|
||||
notify_msg=notify_text,
|
||||
)
|
||||
await create_notify_task(notify)
|
||||
|
||||
cfg.notifies.append(notify)
|
||||
save_notify_config(cfg)
|
||||
DATA_FILE_LOCK.release()
|
||||
|
||||
await evt.send(f"了解啦!将会在 {notify.notify_time} 提醒你哦~")
|
||||
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _():
|
||||
await DATA_FILE_LOCK.acquire()
|
||||
tasks = []
|
||||
cfg = load_notify_config()
|
||||
for notify in cfg.notifies:
|
||||
tasks.append(create_notify_task(notify, fail2remove=False))
|
||||
DATA_FILE_LOCK.release()
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
238
poetry.lock
generated
@ -1033,6 +1033,32 @@ files = [
|
||||
[package.extras]
|
||||
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "imagetext-py"
|
||||
version = "2.2.0"
|
||||
description = "Python bindings for imagetext"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:10578502c27279c3b04d0145374d42904b1fa2ec1f1f2d8f2a8155cbe0759235"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:a91d3b06047b54ca8579647b7b8f65df089be1a1431963c752cd1dddf0ab0d9a"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c8fd07676b189073b7e56811cac9095d95d355dd83b060bf4a3d0fe437953b1"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0f9d9014a8f0c48c8fc7ba7df77b1f8ca75621725aa29f76aec4fd860963e52"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b9420487ffe57272fe39254080ea2f0b2e98fe0d570f1754510092a956807fc"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:de05742ddeb093d21450fc406a22f581a976039a02a5ad2394e5f4ed51090ab2"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66d1b4263025f0b8805c0f2c0405047439f49570f7e87d16d950962ab39f6b89"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3506b59272ee458c91f847cc026759f8a31451e0416ebe8179c260861d88bcf"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eeebba3b2a2517c79bb800e6cb2a49921d9e89866e661736e5db26c5c0ede43c"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e3b8b219afb8f567038ad44923f29b22af04bcd08185d2fea5d9880902b9c4fd"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:b3db2bad720bd0d1656945c94f22d286b479d02d93f9095409ab627b57b8a55b"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:9c342dd2214445c95e89ad9c346956360831fb4075fd38d33e51481674240596"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ae3217cef584faefd30eb9ad41d39e89809ec7c427dc2f916abc80170355213a"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-win32.whl", hash = "sha256:47ced40dffe6cd2a802b40351a5586679d13ad18b88ebf15143f86131f6c4bf4"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-win_amd64.whl", hash = "sha256:d3fbf7e985cc8ac234a210e4b6f439560d902d705610b9af1f5ceb0a61f70933"},
|
||||
{file = "imagetext_py-2.2.0-cp38-abi3-win_arm64.whl", hash = "sha256:be05b30b9301e699b3470ff109f8af28d8ce3e1d9e9738cdbf68e7889b86b7a5"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "8.7.0"
|
||||
@ -1701,6 +1727,216 @@ files = [
|
||||
[package.dependencies]
|
||||
textual = ">=3.7.0,<4.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.2.6"
|
||||
description = "Fundamental package for array computing in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d"},
|
||||
{file = "numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47"},
|
||||
{file = "numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4"},
|
||||
{file = "numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd"},
|
||||
{file = "numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff"},
|
||||
{file = "numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06"},
|
||||
{file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d"},
|
||||
{file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db"},
|
||||
{file = "numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543"},
|
||||
{file = "numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00"},
|
||||
{file = "numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opencv-python-headless"
|
||||
version = "4.12.0.88"
|
||||
description = "Wrapper package for OpenCV python bindings."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "opencv-python-headless-4.12.0.88.tar.gz", hash = "sha256:cfdc017ddf2e59b6c2f53bc12d74b6b0be7ded4ec59083ea70763921af2b6c09"},
|
||||
{file = "opencv_python_headless-4.12.0.88-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:1e58d664809b3350c1123484dd441e1667cd7bed3086db1b9ea1b6f6cb20b50e"},
|
||||
{file = "opencv_python_headless-4.12.0.88-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:365bb2e486b50feffc2d07a405b953a8f3e8eaa63865bc650034e5c71e7a5154"},
|
||||
{file = "opencv_python_headless-4.12.0.88-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:aeb4b13ecb8b4a0beb2668ea07928160ea7c2cd2d9b5ef571bbee6bafe9cc8d0"},
|
||||
{file = "opencv_python_headless-4.12.0.88-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:236c8df54a90f4d02076e6f9c1cc763d794542e886c576a6fee46ec8ff75a7a9"},
|
||||
{file = "opencv_python_headless-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:fde2cf5c51e4def5f2132d78e0c08f9c14783cd67356922182c6845b9af87dbd"},
|
||||
{file = "opencv_python_headless-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:86b413bdd6c6bf497832e346cd5371995de148e579b9774f8eba686dee3f5528"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = {version = ">=2,<2.3.0", markers = "python_version >= \"3.9\""}
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "11.3.0"
|
||||
description = "Python Imaging Library (Fork)"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"},
|
||||
{file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
|
||||
fpx = ["olefile"]
|
||||
mic = ["olefile"]
|
||||
test-arrow = ["pyarrow"]
|
||||
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"]
|
||||
typing = ["typing-extensions ; python_version < \"3.10\""]
|
||||
xmp = ["defusedxml"]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.4.0"
|
||||
@ -2926,4 +3162,4 @@ type = ["pytest-mypy"]
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.12,<4.0"
|
||||
content-hash = "9c52c6203be14fe8411add06d2fc4157f07859ee0037dd247452718ac6a1251d"
|
||||
content-hash = "673703a789248d0f7369999c364352eb12f8bb5830a8b4b6918f8bab6425a763"
|
||||
|
||||
@ -18,6 +18,9 @@ dependencies = [
|
||||
"requests (>=2.32.5,<3.0.0)",
|
||||
"beautifulsoup4 (>=4.13.5,<5.0.0)",
|
||||
"lxml (>=6.0.2,<7.0.0)",
|
||||
"pillow (>=11.3.0,<12.0.0)",
|
||||
"imagetext-py (>=2.2.0,<3.0.0)",
|
||||
"opencv-python-headless (>=4.12.0.88,<5.0.0.0)",
|
||||
]
|
||||
|
||||
|
||||
|
||||